I looked at the benchmarks.
In cases where .NET is faster it's because the C# version is optimized using unsafe code and x86-specific (i.e. non-portable) AVX2 intrinsics to do the math.
Go version is written in straight-forward way. I think all Go programs are shorter than their C# version.
Compare mandelbrot benchmark:
* https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
* https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Those are not fair comparisons and therefore don't paint the correct picture of relative performance.
This is the link you should share: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
https://medium.com/servicetitan-engineering/go-vs-c-part-3-c... - check out "Runtime Performance" section here, it shows that geometric mean on exactly this benchmark is heavily in favour to .NET, and it's .NET 3.1, not .NET 5.
And we have an unsubstantiated claim from you, the Go is faster, and code is shorter, on average. What is this based on?
What to you is a fair comparison?
Presumably unsafe code is not allowed for C# and Go assembly not allowed for Go. Are there any other restrictions? We could do a naive port of one of the Go benchmarks to C# and see how it goes, which one do you think is a good candidate?
I wrote a lot of C# and a lot of Go. C# has so much more ceremony that it is more verbose and it shows even in the code we're discussing. You just have to be willing to look.
Fair comparison between C# and Go is actually very easy. Those languages are so similar that you can transliterate a given benchmark from one language into another. Then benchmark those versions.
There's just no way that on an average program Go (language statically compiled to assembly with a very competent code generator) will loose in performance to C# (which compiles to bytecode and then JITs that code at runtime using a much weaker code generator).
Go is well known for having laborious error handling (prompted by a lack of exceptions) and masses of boilerplate and verbosity precipitated by the lack of various other features, the most glaring of which is an absence of generics. This means implementing custom data structures is generally an exercise in copy paste, or ignoring type safety.
Things like the lack of extension methods, JSON and YAML serialisers that require explicit annotations everywhere instead of conventions, the lack of OO/polymorphism, no ternary operators, null chaining operators, etc. etc. also contribute to the verbosity.
Simplicity is good, but the lack of expressivity and the need for such boilerplate is bad. A pretty poor type system makes it worse. Go has many strengths, but I massively prefer C# for the majority of non-trivial situations.
Regarding performance, it depends heavily on what you're doing. For example, Go's allocator and GC is designed to optimise for low pause latency, whereas dotnet is optimised more for high throughput and good cache coherency. Given the extent to which most apps are stalled waiting for memory, the lack of good cache coherence in Go allocations, and the lack of a generational GC can absolutely decimate performance. DotNet is capable of allocating at 25x the speed of Go, for example.
Go read https://medium.com/servicetitan-engineering/go-vs-c-part-3-c...
The Go mandelbrot program you looked at is a little larger than one of the C# mandlebrot programs.
816 C# .NET #9 program
894 Go #3 program
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
1. First, unsafe doesn't mean you shouldn't use it on .NET. It just means you need to do more checks manually.
2. A lot of things you can do in Go are unsafe in .NET terms - e.g. even slice is a leaky & unsafe abstraction: https://alexyakunin.medium.com/slice-an-extremely-leaky-abst...
3. Yes, the fact Go doesn't support SIMD intrinsics explains why it loses not only to C#, but also to C++ and Rust on math-intensive tests. But it loses to C# on other tests too - e.g.: - https://benchmarksgame-team.pages.debian.net/benchmarksgame/... - https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
And as you might notice, the code length doesn't differ much there.
Go has support for assembly and supports SIMD intrinsics just fine. See for example https://github.com/bamiaux/rez/blob/master/vscalers_amd64.s
My point is that if you want to KNOW which language is faster (as opposed to trying to PROVE that YOUR language is faster) you wouldn't compare a C# code optimized with SIMD intrinsics with Go code that doesn't use SIMD intrinsics.
The problem with BenchmarksGame is that it doesn't try to enforce apples-to-apples benchmarks.
It's fun thing to see how far you can push a given implementation if you're willing to spend a lot of time on it.
It compares implementation of the benchmark code, not the quality of the compilers on the code that you'll actually write in real life.
Sorry, I missed the proof - can you point me to it?
What you presented as "more verbose code" isn't actually a proof - i.e. yes, SIMD code is obviously more verbose than a normal one. And faster.
> Go has support for assembly and supports SIMD intrinsics just fine.
But wait, in this sense any language has support for assembly and SIMD. Bundled assembler is not the same as language-level support for SIMD - and even in https://benchmarksgame-team.pages.debian.net/benchmarksgame/... a large portion of SIMD code is actually cross-platform (what uses Vector<double>), and I am pretty sure sticking to just cross-platform SIMD APIs would be enough to beat Go.
> You wouldn't compare a C# code optimized with SIMD intrinsics with Go code that doesn't use SIMD intrinsics.
You use what's not against the rules, and it's not against the rules on CLBG. You're free to submit your own version of the same benchmark on Go relying on SIMD or whatever you prefer.
> It compares implementation of the benchmark code, not the quality of the compilers on the code that you'll actually write in real life.
Yes, any benchmark is somewhat biased. But honestly, comparing real-life benchmarks is even harder - they involve much more components, so whoever isn't happy with the results can always claim it's a comparison of frameworks, not the actual programs, etc., etc.
Go and C# are so similar that for benchmarks you can transliterate one into the other.
We should be comparing programs that are comparable.
My point is that BenchmarksGame is not comparing comparable programs.
Code for some languages has extreme optimization, including doing things that most people don't do in day-to-day programming.
Go supports assembly. Given enough time I could probably implement a given benchmark in assembly, beating C# (and pretty much anything).
This is used to good effect in Go runtime and some really niche applications but in real life I don't have infinite amount of time to micro-optimize my code and write parts of it in assembly.
What I want to know is the performance of competently written code.
Is this "competently written" ?
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
I think the fact that Go compiles to native executables as the default, just gives the impression that it is "low level". That and the lack of features I suppose.
I say all of this as someone who loves Go as a language by the way. C# could use some simplification!
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
But unlike GO, you will need to write 50x less lines of code to achieve the same result.