I'm not one to hate on C#, or be a programming language snob but this certainly looks like a case where poor performance and a lot of extra work were created simply because of a deficiency in a language. Languages like C# are advertised as being simple to use, and for the most part they are. They fit the bill in a lot of different use cases.
But it certainly seems like to me that if you want to build a high-performance, scalable piece of software, you don't want to have to bang your head against wall and fight against deficiencies within the language implementation itself in order to get your software working properly.
You are conflating the language with the runtime, first. And second, we were experiencing the occasional page taking maybe one second, which we considered unacceptable but 99% of the world wouldn’t notice.
(NB, languages like Ruby and PHP are lovely, but are over 10x slower than C# and Java.)
I'm so tired of benchmarks that play with ints and floats which show how fast Java is.
Most business app work is string manipulation. If you think Ruby is slow, look at the timings for "sequential" operation in the table on this page (yes, it's my site):
FYI: I'm not trying to say that "Ruby is the most awesomest language, like ever, d00dz!!!". I like different tools for different jobs. I'm just tired of seeing people judge implementation speeds based on bit twiddling benchmarks, rather than stuff that at least churns through a large number of strings, if not other object types, and does some I/O.
I'm not sure, but I think the Perl/Python code sends the strings as arguments to print that will just output them directly. In Java you will concatenate 3 strings before sending it to "print". This adds some extra CPU usage that the other versions don't have
One item of possible note: It wasn't possible to have list driven output syntax in Java before 1.5. I'm not sure if they added an output method with elipses in it then, or not. Even if so, I'm not sure it would be faster.
Still, I could modify the scripting output lines to bring them down to Java's level :-)
You're comparing the library-supplied date formatter for each language, not the language's speed at processing Strings. And the Java threading code is mostly benchmarking the speed of thread creation - in a real-world implementation you'd be using a thread pool with fewer lines of code.
Agreed about the thread usage: the code I put together for threads in various languages is as naive as possible. Having a thread pool in proportion to the number of CPUs and pulling tasks from a queue (a la "Nginex") would be much more efficient.
Interesting comment about the date formatter. I might put in something some time to compare the relative time spent in formatting vs the other concatenation. I suppose I'd be grateful if somebody made a fork with versions showing the split of time between those steps.
Yes, sorry, I meant implementation of the language, ie. CLR.
That being said, having to rewrite an entire engine because of the underbellies of the CLR seems to be dubious, especially in the case of a development environment that purports to make life easier for the developer.
I have nothing against C#, one of the trading frameworks I use uses it exclusively (Ninjatrader) and it's pretty nice. It's just that I would hate to have invested weeks/months into a software project, using what I imagine would be tried-and-true software techniques, and then have to rework them to get over the particulars of the implementation.
That being said, I guess all languages have similar problems. For example, when I was working on a backend server back in 2001, we found that our product was "leaking" memory on HP-UX, even though none of memory leak detectors found any problems, and the memory leak problem didn't occur in Solaris, AIX and Windows (we had a cross-platform server). It turns out on high-load systems, our app was allocating a bunch of small strings all over the place, and the base memory allocator for HP-UX was causing memory fragmentation over time. By switching to another memory allocator that handled this situation, it fixed the problem.
I guess there aren't any C/C++ books that I've come across that say "don't allocate a millions of small memory blocks because your memory might fragment, even though you free them properly." So maybe I misspoke, I guess to some degree it does manifest itself in all implementations of languages.
Some languages solve this problem by not having a GC at all :) However, with a problem involving huge in memory structures like this, even manually allocating and deallocating everything properly would probably be a non trivial thing.
I can't say that the Java Virtual Machine would have done much better, since it operates under pretty much the same theory (generational garbage collection).
At least Ruby has the option to mark some strings as outside of garbage collection -- to make them permanent symbols/atoms.
We need an option in these modern GC languages to select a reference counting option, or perhaps for portions of code to kick it old school and simply ask for some objects to allocated outside the GC heap on the assumption that they will be around for a while and that the programmer will manually throw that subset of objects away if they become unwanted.
TMTOWTDI. (and all ways seem to have their place at times)
You can intern strings manually in .NET (I think you can in Java too), which effectively makes them ineligible for collection. There are serious memory concerns with that approach, since nothing in the tag engine is a constant.
In C# you can use the unsafe keyword to get more or less back into the C/C++ world. While your new'd objects are still GC'd, you have the option of just grabbing an allocator and getting unmanaged memory if you feel like it.
It's worth noting that the .NET GC works quite well for typical cases, and only noticeably chokes on this one use case we have and only under load that most websites will never see (and most users don't notice even on SO, but we watch the logs religiously to make sure these things don't become noticeable). There are also some improvements coming in .NET 4.5's GC that may mitigate this, but we're naturally not willing to wait for it.
I worry people may be taking "don't use .NET, its GC sucks" away from this blog post, which really isn't the point (or accurate).
I worry people may be taking "don't use .NET, its GC sucks" away from this blog post, which really isn't the point (or accurate).
I get the feeling some already came in with that opinion, so they will take away what they want to. I personally got the impression that this is something that would have caused pain in almost any language with a generational GC.
I definitely do NOT mean to imply that the .NET GC is inferior. The very fact that you have options of how to manage memory at all in C#/.NET makes it superior to the JVM in that regard.
Admission: I'm am reluctant to want to work on Windows, though. But since that is the Stack Exchange environment, C#.NET seems hands-down the best platform for it.
But it certainly seems like to me that if you want to build a high-performance, scalable piece of software, you don't want to have to bang your head against wall and fight against deficiencies within the language implementation itself in order to get your software working properly.