4 ms·
> Myth 2: It’s Slower than Node/Python/Go/Rust This feels disingenuous. The author uses this heading for proof that ASP.net performs faster than similar framew
by DoctorOW 5y ago
> Myth 2: It’s Slower than Node/Python/Go/Rust
This feels disingenuous. The author uses this heading for proof that ASP.net performs faster than similar frameworks in Node/Python. I could be convinced C# is faster than Go, but absolutely not for Rust. The simplicity modern C# provides (look at those code samples) comes at the cost of runtime performance optimizations.
- pharmakom 5y agoBenchmarks would be required to prove it, but I could actually see .NET outperforming Rust in a few scenarios. First, C# can be written in a way that stack allocates almost everything (much like Rust) and second, the runtime information and JIT compilation may allow it to make better optimisations.
- Yoric 5y agoI'm a big Rust fan but I fully expect that C# can beat Rust in some benchmarks and actually in some useful scenarios. However, claiming outright that .Net outperforms Rust feels like an apple-to-petticoat comparison.
- DoctorOW 5y agoOnly if you're including compile time in the benchmarks. Binary to binary, JIT is a great example of Rust having a compile-time optimization that .NET implements at runtime.
- Yoric 5y agoWell, some optimizations can only be implemented at runtime, so comparing Rust and C# without knowing the actual scenario doesn't seem to make much sense.
- woodruffw 5y agoOptimizing compilers and JITs are difficult to compare directly: JITs have optimization pressures (e.g., selecting instructions/register slots as rapidly as possible) that AOT compilers don't (and vice versa), and (similarly) tend to have simpler IRs. In general, even the best JIT is going to underperform an AOT optimizing compiler for those reasons. Microbenchmarks (and compiler quality) will always vary, but the macro picture is difficult to change.
- pcwalton 5y ago> the runtime information and JIT compilation may allow it to make better optimisations. In practice this mostly means speculative devirtualization. This is absolutely true for C++, which tends to use virtual methods a lot, but Rust doesn't use virtual methods much. Moreover, profile-guided optimization (PGO), which Rust supports [1], allows the Rust compiler to take advantage of these speculative sorts of optimizations just as .NET does. Granted, PGO is annoying to set up compared to the .NET VM, which "just works". PGO'd Rust is deployed in production, though. [1]: https://doc.rust-lang.org/rustc/profile-guided-optimization.html https://doc.rust-lang.org/rustc/profile-guided-optimization....
- darksaints 5y agoI'm not sure about this specific case of Rust vs .NET, but the theoretical benefits of JITs never really seem to play out in practice, except for dynamic languages that can get really big improvements by using types speculatively. I think that one of the things that JIT proponents seem to miss is that JIT compilers have practical limits to the scope of analyses and optimizations that can be done...quick, single pass analyses, basic inclining, etc. An AOT isn't relying on competing with runtime resources to analyze and optimize code, and it can take a lot of time to do whatever it needs to. I've found that AOT with PGO is the performance holy grail for just about any use case.
- int_19h 5y agoThere's one big benefit that JIT brings to the table that is not at all theoretical: it can devirtualize and inline across shared libraries. This doesn't matter if you link everything statically, of course, but that's not always desirable. (Another benefit is that it allows for generic virtual methods, but that's only indirectly a perf thing.)
- hackerfromthefu 5y agoWith .NET it's been really interesting watching the journey to greater and greater performance - there's been so many performance optimizations that weren't implemented for 1-2 decades. So .. watch this space, possibly JIT performance will get improved more when they run out of lower hanging fruit.
- celdon25 5y ago> the runtime information and JIT compilation may allow it to make better optimisations That's a very, very slim "may", at least before .NET 6 (I don't keep up with .NET anymore.) https://web.archive.org/web/20100627105951/http://blogs.msdn.com/b/davidnotario/archive/2005/08/15/451845.aspx https://web.archive.org/web/20100627105951/http://blogs.msdn...
- deleted 5y ago[deleted]
- tialaramex 5y ago> C# can be written in a way that stack allocates almost everything (much like Rust) I'd be surprised if this works in practice because the String processing in C# is surely going to keep making Heap objects ? You're immediately in a better place here in Rust because people (sensibly) keep developing standards encoded in UTF-8 and so the bytes on the wire are Rust's built-in str type, whereas C# needs to turn them into UTF-16 and store that somewhere as a String.
- briHass 5y ago> I'd be surprised if this works in practice because the String processing in C# is surely going to keep making Heap objects ? The new Span<T>, specifically Span<char>, stuff allows you to slice and read strings without creating new objects, and string has both a c-tor for a (readonly) span and a Create method that takes a delegate that allows you to fill the string already allocated on the heap.
- tialaramex 5y agoI didn't know about Span<T>, but it makes sense to give C# slices somehow. However so far as I've seen while writing C# popular APIs want an actual String and they won't take these slices as a substitute? The ergonomics seem poor. Maybe I'm mistaken and magically my C# code which says "string" everywhere is actually converted at runtime to use Span<char> and go real fast? But it doesn't look like it. The Rust APIs really do take the slice reference &str, it's just normal in Rust to say &str unless you very specifically want a mutable String for some reason (e.g. you're going to insert stuff into it)
- dehrmann 5y agoI'm not sure if .NET can do this, but Java is similar, and it can do escape analysis to keep more things on the stack.
- littlestymaar 5y ago> First, C# can be written in a way that stack allocates almost everything (much like Rust) While it works (and game developers using Unity tend to use that A LOT to get decent performances), it's also an enormous pain in the ass because you lose most of the “modern” features of C#.
- mhh__ 5y agoJITs precisely can provide runtime performance optimizations. What makes C#/Rust special? If you can't name anything in rust that would actually effect the dataflow analysis then you may need to reconsider.
- FridgeSeal 5y agoRust having one of the most sophisticated optimising compiler backends? And a whole suite of language design choices that enable fast, correct code?
- mhh__ 5y agoThe parent comment is clearly talking about language design rather than the backend. I say this because I often see Rust people say isn't a great that rust can do xyz and then I look into it and it's actually just basic dataflow analysis that any compiler does or just LLVM being clever.
- dehrmann 5y agoA JIT gives you the ability to target the current CPU better.
- osigurdson 5y agoI'd say the primary factor is that C# has a garbage collector while Rust does not. C# and Rust are not really in the same league in my opinion. C# is more of a Java and Go competitor while Rust competes with C for the most part.
- mhh__ 5y agoThat's very dependant on the program being worked on. Garbage collection can make certain programs harder but I promise you can write absolutely awful memory allocators in any language.
- int_19h 5y agoC# has some features that make it lower-level than Java or even Go. For example, it has pointers with pointer arithmetic, C-style unions, and explicit stack allocation of structs and arrays. In fact, the only two things in C that doesn't have a straightforward and efficient 1:1 translation to C# are signals and setjmp/longjmp (although the latter still maps very closely to exceptions).
- Rochus 5y ago> but absolutely not for Rust Right. Here are measurement results based on the Are-we-fast-yet benchmark suite: https://github.com/rochus-keller/Oberon/blob/master/testcases/Are-we-fast-yet/Are-we-fast-yet_results_linux.pdf https://github.com/rochus-keller/Oberon/blob/master/testcase.... The version of the benchmark translated to C and compiled with GCC or CLANG -O2 runs about twice as fast as the CLI/.NET version. Rust's performance is close to C's. And before you say that Mono is slower than the CoreCLR have a look at these measurements: https://www.quora.com/Is-the-Mono-CLR-really-slower-than-CoreCLR/answer/Rochus-Keller https://www.quora.com/Is-the-Mono-CLR-really-slower-than-Cor.... But apparently bringing data is a waste of time.
- rndgermandude 5y ago>But apparently bringing data is a waste of time. Frankly, bringing apple production data to an orange framers' convention is a waste of time... I keep seeing you pop up in comments what feels like every time there is something about C# or dotnet or CoreCLR, again and again with your questionable comparisons and "data": - You're compiling Oberon+ to CLR/IL code using your own compiler. Oberon+ is a language you yourself maintain it seems. It's not C# or F#, which are by far the dominant languages for dotnet. To me at least, Oberon+ seems like a rather esoteric niche language without wide adoption, but I could be missing something. - The quality of the codegen your Oberon+-to-CLR/IL compiler manages to achieve compared to the dotnet compiler that people would actually use most of the time, that's a big unknown. But I see a real chance that the dotnet compiler, that saw countless hours of development time from a large team of some of the brightest domain experts that MS could find, is outperforming your compiler's codegen. - How well Oberon+ translates to CLR/IL (or CIL, basically bytecode for compatible .NET runtimes) is another unknown (is it straight forward, does it require the compiler to add a lot of "glue" code or structures to accommodate that language?) - You're not running your benchmarks on the dotnet CoreCLR, but on mono. And you're trying to handwave this important fact away by linking one of your own quora posts that again uses your own Oberon+-to-CLR/IL-with-my-own-compiler benchmarks that allege to show that there isn't much of a difference between mono and the CoreCLR runtimes. Maybe there isn't, or maybe there isn't just for the very narrow specific IL your Oberon+ compiler produces for the Oberon+ benchmark code you use. But even looking at your own results in your quora post, there seems to be a significant difference in performance even with your narrow use case when comparing mono to CoreCLR 5/6 performance, in favor of the CoreCLR. - You're running the result of what your own Oberon+-to-CLR/IL compiler spits out on mono-3 (last release 2015, EOL) and mono-5 (last release 2019, EOL) runtimes. Current stable mono-6 was released in 2019. So you're not even running on a current mono release, let alone a current CoreCLR release. The old (mono) runtimes and standard libraries lack a lot of performance-related features that modern CoreCLR versions have (especially when it comes to value types, Span<> and stackalloc, etc, that can be used explicitly in code or in a lot of cases even implicitly by an optimizing compiler) - You're running on rather old hardware, and a laptop hardware no less. The Intel Core Duo L9400 you mention was released in Q1'06, but according to my google-fu the HP EliteBook 2530p actually uses the SL9400 (is that a typo in your benchmark results pdf?), which was released in Q3'08. It still only comes with DDR2. Would be interesting to know what storage option yours has (as cold-start times of your benchmarks might be dominated e.g. by a slow 5400 rpm laptop grade HDD that is one of the 2530p's storage options). And you run benchmarks on a 32 bit OS. All of which is fine, if you're interested in results on such hardware, but I'd think most people would be more interested in results on slightly more modern hardware. - You managed this time to comment on a Rust-related post, agreeing that Rust is probably faster, trying to justify this assertion with a set of benchmarks that do not include Rust whatsoever, just saying that Rust performance might be close to C. Which is not a bad hypothesis to start with, but when you go on linking your data and nonchalantly proclaiming that "bringing data is a waste of time" when you didn't bring any data regarding Rust, then I don't get your point.