Comment by gw2
2 months ago
C#. While a popular language, it is criminally overlooked for high-performance programming. Obviously, you can't use it for embedded or kernel development. For other use cases though, it can almost reach the performance of C/C++/Rust when written with proper care.
> Obviously, you can't use it for embedded
Embedded is diverse. I would not use .NET for small embedded, i.e. stuff running on Arduino or ESP32.
However, I have successfully used .NET runtime in production for embedded software running on top of more performant SoCs, like 4 ARMv7 cores, couple GB RAM, Linux kernel. The software still has large pieces written in C and C++ (e.g. NanoVG rendering library) but all higher-level stuff like networking, file handling, and GUI are in memory-safe C#.
You surely can use it for embedded,
https://learn.microsoft.com/en-us/archive/msdn-magazine/2015...
https://www.ghielectronics.com/netmf/
https://www.ghielectronics.com/sitcore/
https://www.wildernesslabs.co/
I sometimes write C# in my day job. But I think I don't know much about how to write really fast C#. Do you have any recommendations for learning resources on that topic?
Sure. Here are some resources:
* Span<T>: https://learn.microsoft.com/en-us/archive/msdn-magazine/2018...
* C# now has a limited borrow checker-like mechanism to safely handle local references: https://em-tg.github.io/csborrow/
* Here is a series of articles on the topic: https://www.stevejgordon.co.uk/writing-high-performance-csha...
* In general, avoid enterprise style C# (ie., lots of class and design patterns) and features like LINQ which allocate a lot of temporaries.
LINQ is fine (but enterprise style never is, yes), it’s a matter of scale and what kind of a domain the code is targeted too. C# needs to be approached a little like C++ and Rust in this regard. Having standard performance optimization knowledge helps greatly.
Also can recommend reading all the performance improvements blog posts by Stephen Toub as well as learning to understand disassembly at a basic level which .NET offers a few convenient tools to get access to.
1 reply →
Thank you. I once read a bit about Span<T>, but some of this reference stuff is very new to me. Interesting, definitely. C# really is a big language nowadays...
1 reply →
C# is specifically designed for enterprise-style OOP, so if you want to avoid that, why use C# at all?
16 replies →
Span<T>, ReadOnlySpan<T>, Memory<T>, CollectionsMarshal, CollectionsExtensions, ref struct, ref return, ArrayPool, ArraySegment, ValueTuple, and using interfaces/structs/generics carefully.
That is if you don't want to get into unsafe code.
A few important ones: - Avoid memory allocations as much as you can. That's a primary thing. For example, case insensitive string comparisons using "a.ToUpper() == b.ToUpper()" in a tight loop are a performance disaster, when "string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase)" is readily available. - Do not use string concatenation (which allocates), instead prefer StringBuilder, - Generally remember than any string operation (such as extracting a substring) means allocation of a new string. Instead use methods that return Span over the original string, in case of mystr.Substring(4,6) it can be a.AsSpan(4,6), - Beware of some combinations of Linq methods, such as "collection.Where(condition).First()" is faster than "collection.First(condition)" etc.
Apart from that (which simply concerns strings, as they're the great source of performance issues, all generic best practices, applicable to any language, should be followed.
There are plenty resources on the net, just search for it.
You actually can use it for embedded and kernel development! See .NET Nano Framework [1] for embedded - works on microcontrollers like ESP32. For kernel development there's nothing really built in to support it but people have built tools [2] to do it.
[1] https://nanoframework.net/ [2] https://gocosmos.org/
Pour one out for Midori, which would have replaced Windows with a capability-based OS completely written from kernel to shell in a C# dialect. Async/await, spans, and immutable support came from it, along with an (opt-in) Rust-like borrow checker. Satya canceled it, and all the work was lost to history. Singularity was the early public prototype.
The only thing Singularity and Midori share is the idea.
You should also pour one out for Longhorn, where internal politics tanked the idea, and eventually Windows team redid all those .NET based ideas into COM/C++, and were even proud of doing so (see Hilo sample documentation), hence why nowadays COM based libraries are the main way to expose modern Windows APIs (aka post Windows XP).
Had they collaborated instead, probably Windows would be closer to something like Android userspace nowadays.
Or for Ironclad, another one from Microsoft research, lesser known, also from the same research group, which even includes type safe Assembly,
https://www.microsoft.com/en-us/research/publication/safe-to...
Microsoft Research has plenty of work in such domains, they also had a LLVM like compiler framework, based on MSIL, called Phoenix, among other stuff, e.g. Dafny, FStar, Drawbridge, also come from OS projects.
Unfortunely classical Microsoft management has been more like it isn't Windows, it isn't shipping.
3 replies →
And arguably it beats the performance of C/C++/Rust when written without proper care: https://blog.codinghorror.com/on-managed-code-performance-ag...
The big take-away I got from this (admittedly quite old now) experiment is that getting advertised performance out of unmanaged languages for typical real-world (i.e., non-benchmark) tasks often requires a lot more care than people really account for. Nowadays memory dominates performance more so than CPU, and the combination of a JIT compiler and a good generational, compacting garbage collector - like C# and Java developers typically enjoy - often does a better job of turning idiomatic, non-hand-optimized code into something that minimizes walks of shame to the RAM chips.
Well in that case, Java :)
I've been having a lot of fun with Java lately, the maturity of the language/implementation and libraries allows me to focus on the actual problem I'm solving in ways no other language can currently match.
https://github.com/codr7/tyred-java https://github.com/codr7/eli-java
[dead]