Bjossi on 3/12/2008 at 21:26
Why is C# slow anyway? I've only learned the basics so I'm kind of confused here. :erm:
Al_B on 3/12/2008 at 21:43
C# compiles to an interpreted language and not to native code. Other languages in the .net family also compile to the same bytecode which helps when mixing C# and visual basic (for example). Unless CIL / MSIL instructions are built into processors it's going to be slower to execute than native code.
To be honest, I wouldn't say that C# is slow - but it's not the fastest possible language.
Phatose on 3/12/2008 at 22:43
Quote:
C# compiles to an interpreted language and not to native code. Other languages in the .net family also compile to the same bytecode which helps when mixing C# and visual basic (for example). Unless CIL / MSIL instructions are built into processors it's going to be slower to execute than native code.
Incorrect. That's how Java works. C# and all .net languages work differently.
In particular, You've missed a step - unlike java, which is run as bytecode in a virtual machine, C# is distributed as bytecode, and just in time compiled to native code. C# (and vb.net, all the .net languages) will start up slower as they JIT compile, but they do not have the performance overhead of an interpreted language.
Additionally, you have the option in Visual to pre-compile directly to native code.
Quote:
We're discussing games here (and that was the context of my original remark), of course the code is going to get optimised. And your comparison between C# and 'unoptimised' C++ is just bizarre.
And as was already pointed out, they aren't using it for their rending engine. But they still need installers, frontends. You think somebody is going to optimize the code for their installers?
That takes time and dev money. C#, as much as it's a language, is completely tied into the .net framework. Ease of use and pre-optimized code, for most major functions. They ain't going to re-invent the wheel.
Yakoob on 3/12/2008 at 22:47
Quote Posted by Al_B
When I create an app that only uses forms - why shouldn't I only have to include the distributable parts of the namespaces that I use?
DLL HELL
Quote Posted by Al_B
C# compiles to an interpreted language and not to native code. Other languages in the .net family also compile to the same bytecode which helps when mixing C# and visual basic (for example). Unless CIL / MSIL instructions are built into processors it's going to be slower to execute than native code.
To be honest, I wouldn't say that C# is slow - but it's not the fastest possible language.
Isn't the bytecode compile to machine language when you launch it (JIT compilation), thus being just as efficient as one compiled straight to machine cocde in first place?
C# is slower than C++ in the same sense that C++ is slower than assembler.
Phatose on 3/12/2008 at 23:27
Yes, it's JIT - causes a slower startup.
To answer the original question, the performance penalties it has are due to type safety and garbage collection. .net checks a reference to make sure it is what it's supposed to be before it uses it. Adds in an extra step, but makes sure you don't accidentally get a foo when you wanted a bar, and then proceed to overwrite memory incorrectly.
GC alone is enough to disqualify it from time-critical apps. It's managed memory, which means 95% of the time we don't have to worry about remembering to call a destructor and free up memory. The GC automatically nukes variables and reclaims the memory when they go out of scope, or when the last reference to it is gone. It doesn't prevent all memory leaks - there are a few classes you have to remember to destroy, and circular references can fuck up the GC - but it stops many if not most of them. And if you've every had a leaky app, you know that's a good thing.
The thing is, we don't control it. Means we don't have to worry about it, fewer memory leaks and higher productivity. Unfortunately, we don't control when it runs. Which is why you can't make time sensitive apps in .net. It's all well and good when the GC decides to eat up some CPU cycles in your business app. Slow for a bit, but you get it right back from the memory reclaimed.
If, however, it decides to run right in the middle of you ApplyRadiationDosage routine on your radiotherapy machine.....well, you're looking at some Radiation poisoning, shortly to be followed up by the equally lethal lawyer poisoning.
Yakoob on 4/12/2008 at 00:01
Phatos, I cannot cite specific sources, but I was reading that everything you said has been pretty much debunked. The startup-slowdown is minimal and, past that, the machine-language compiled code runs just as efficiently as any other. Further, while GC causes some slowdowns, they are rather insignificant in the big picture; they're certainly not the dramatic "fuck up everything if running at the wrong time" triggers you make them sound to be. Odds are you wont even notice when they are run.
Lastly, stating that we have no control over GC is just plain wrong - there is several ways you can tweak how GC works and how objects get deleted in managed languages.
Chade on 4/12/2008 at 00:40
I don't know much about C#, but if circular references are still a problem with the latest runtime environments I will eat my non-existant hat.
The Java runtime is also getting a lot faster. I believe most objects are now allocated on the stack rather then the heap (don't quote me on this though).
I was writing a java convex optimisation program recently (couldn't find a free one not under the GPL), and on the basis of some old Java myths I built a matrix pool so I didn't have to allocate the memory for matrices in each step. Much to my surprise, once I implemented the matrix pool throughout the program, I found it made absolutely no performance difference whatsoever. I wouldn't be surprised if the JVM was just reusing the same memory in each step anyway.
(
http://www.research.ibm.com/ninja/) These guys reckon they can made a jre perform around 90% as fast as heavily optimised fortran.
Phatose on 4/12/2008 at 01:08
Quote Posted by Yakoob
Phatos, I cannot cite specific sources, but I was reading that everything you said has been pretty much debunked. The startup-slowdown is minimal and, past that, the machine-language compiled code runs just as efficiently as any other. Further, while GC causes some slowdowns, they are rather insignificant in the big picture; they're certainly not the dramatic "fuck up everything if running at the wrong time" triggers you make them sound to be. Odds are you wont even notice when they are run.
Lastly, stating that we have no control over GC is just plain wrong - there is several ways you can tweak how GC works and how objects get deleted in managed languages.
There is a reason I picked the words time critical and radiation treatment as an example. I was actually quite agreeing that once compiled, it's just as fast, and very small startup times and no startup times aren't the same thing.
Is there a way to stop the garbage collector from running at specific times? I'll be happy to be wrong here. What settings in particular? I know about GC.collect, and that you can force it to run at a specific point if you need it to, but what about stopping it?
Chade, are those shallow circular or deep circular references you're offering hat eating, just so we know what we're talking about. A points to B and B points to A and nothing else points to either is probably well handled, but what about A points to B points to C points to a collection points to A?
Either way, now I am genuinely curious. If there's not a startup delay and GC can be controlled, why the hell aren't we programming games and shit in this?
dvrabel on 4/12/2008 at 01:50
Quote Posted by Phatose
Either way, now I am genuinely curious. If there's not a startup delay and GC can be controlled, why the hell aren't we programming games and shit in this?
There are a number of possible reasons, some of which have nothing to do with language features.
* Availability of experienced staff.
* Existing code, libraries, build/test systems.
* Third party libraries or code may only be available for certain languages.
Chade on 4/12/2008 at 02:02
Quote:
Chade, are those shallow circular or deep circular references you're offering hat eating
It doesn't make a dime of difference with recent JVM's, because the gc won't even touch the offending classes.
A quick disclaimer: the method I describe here is not, I believe, the only way which modern JVM's do gc. In particular, I believe objects which are not refered to outside the scope in which they are declared are handled much more efficiently and do not live outside the scope they were created in. But I am no expert, so take this with a grain of salt.
Assuming an object find its way onto the "long-lived object" heap, however, the gc still doesn't have a problem with circular references. It doesn't do reference counting. Instead it lists objects which are still referred to from a runnable thread, and lists objects refered to by those objects, and so on, until it has found a list of all objects which are still reachable from a runnable thread. Those objects are then "kept".
I won't say that the JVM throws out the gc'd objects, because from a performance pov it actually doesn't ... it just fails to keep them. The efficiency of this process is completely different to C - which does work for each object deleted. A modern JVM has to do work for each object it keeps - the ones deleted are entirely free. The JVM will therefore try to call the garbage collector when it thinks it won't have to keep many objects, and if it does a good job (which of course it might not) it could potentially be faster then C.
But AFAIK, all these optimisations are still being actively developed, and I imagine that the JRE's still have a long way to go before being as fast as C/C++ on average. Besides, I imagine all the good gaming libraries and game programmers would still be primarily C/C++ programmers.
And the programmer still won't have fine-grained control over exactly when stuff happens, so critical applications might still want to use lower level languages.