3 ms·
C# and Java are almost always faster than Go. Go isn't fast, it's decent but nothing special for AOT native code. (atleast the standard gc compiler, llgo, gccg
by jpgvm 4y ago
C# and Java are almost always faster than Go.
Go isn't fast, it's decent but nothing special for AOT native code. (atleast the standard gc compiler, llgo, gccgo etc could end up being a different story). It can show good overall performance in I/O bound workloads because of native M:N green threading though.
I imagine even that is no longer a point in Go's favor when Java's Virtual Threads land and become widespread however.
Go's only real interesting runtime feature was their emphasis on having a very low latency GC. This was somewhat special for a few years but between improvements made to .NET and Java's new GCs (Shanandoah and ZGC) that gap has been eliminated while these runtimes still provide better throughput on top of their now low latency.
There really isn't a good performance or resource usage reason to pick Go over C#/Java anymore, all of its advantages have been eroded.
- erik_seaberg 4y agoGo’s GC throughput isn’t great, but they’re pretty good at keeping values off the heap. Java’s GC is amazing, but we’ll have big working sets and boxing overhead until value types land.
- kaba0 4y agoI would go as far to say that Go’s performance is good only because of value types. Their GC is known to slow down allocation when under big pressure.
- Groxx 4y agoI was poking into a 7-10 second test a couple years ago out of curiosity, and pulled a tracing profile. Garbage collection accounted for over 95% of the run-time. It was a perfect pathological case where it continually thrashed below/above a GC threshold, without hitting the point where it would make more room. Adding just a couple kilobytes of ballast[1] pushed it over the limit to where it reliably took about 200ms. (and then I rewrote the test to stop allocating so much junk) Go's GC is mostly pretty good in practice, but yeah. It's definitely not something you can rely on blindly. Also I wish they'd stop claiming that its pause times are tiny - the stop-the-world pauses are indeed consistently very short, but it hardly matters when it can pause goroutines for far, far longer[2]. And e.g. when you're allocating, your goroutine may be paused to "help" the GC, which can take a substantial amount of time (as happened in that^ test), which frequently leads to very large tail-latency. Most people don't care about stop-the-world times, they care about tail-latency, and Go is just leaning on people's misunderstanding that one is the cause of the other. It can be, but it's not the only source. [1]: https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap/ https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i... [2]: http://big-elephants.com/2018-09/unexpected-gc-pauses/ http://big-elephants.com/2018-09/unexpected-gc-pauses/ among other sources of individual goroutine pauses.
- morelisp 4y agoIt's still possible to pace the GC like this in certain cases, but most specific benchmarks before the preemptive scheduler introduced in Go 1.14 aren't particularly relevant anymore. Today I think that Twitch blog post does more harm than help. (And even at the time, while an interesting case to analyze, the right fix is usually "make less garbage", not "add some ballast".)
- Groxx 4y agoOh yeah, completely agreed. The GC does keep improving, and that post is much less relevant than it used to be. It does still apply in some niches though :) I think Go's GC is solidly "good enough", and much better than many languages, so I broadly like it. Coupled with built-in tracing that shows GC activity and it's in a pretty good position. It's more that all GCs have pathological behavior somewhere, and no amount of distracting hand-waving changes that.
- kaba0 4y agoGo’s GC are not low-latency in the ZGC Shenandoah meaning - it just slows down allocation (and thus every thread) under big pressure.
- jpgvm 4y agoTechnically so do ZGC/Shanandoah/C4. All three use load-barriers which result in more work done in application threads as the pressure on the GC increases. That said these GCs are substantially better than the Go GC so you are talking about much higher allocation throughput before running into these issues in practice vs Go.