Live data from Hacker News

Generics can make your Go code slower

planetscale.com

321–330 of 418 posts

Re: Generics can make your Go code slower

#321

Earlier quoted context omitted.

250 vs. 50000 req/s seems like a too big of a difference to me. Sure Go is faster than Node but Node is no slough either, you might want to dig in some deeper why you only got 250 req/s with Node.

That could mostly be due to multithreading. That comes free with go but requires a different model in node.

50000/250=200, that is a lot of cores!

Re: Generics can make your Go code slower

#322
post #46

I'd argue that golang is inherently not a systems language, with its mandatory GC managed memory. I think it's a poor choice for anything performance or memory sensitive, especially a database. I know people would disagree (hence all the DBs written in golang these days, and Java before it), but I think C/C++/Rust/D are all superior for that kind of application. All of which is to say, I don't think it matters. Use t…

Ultimately, Vitess is good so any argument that concludes that it must be bad is not using evidence.

Re: Generics can make your Go code slower

#323
post #7

> there’s no incentive to convert a pure function that takes an interface to use Generics in 1.18. Good. I saw a lot of people suggesting in late 2021 that you could use generics as some kind of `#pragma force-devirtualization`, and that would be awful if it became common.

Why would that be awful?

First, because `[R io.Reader]` is an awful way to spell "force devirtualization". It's not explicit about what it means, and it's not derivable from first principles like Go's other odd spellings, e.g. `interface{}` or `var _ Reader = T{}`, are.

Second, it doesn't really promise to devirtualize it. If what I have is a variable of type `io.ReadCloser` - not just implementing it, but already boxed - it's not going to be able to unbox it for me.

Third, if that was all or even primarily what we wanted out of generics it would've been much better to spend the past two years hacking on the inliner and other parts of the compiler to improve devirtualization.

I don't think it would be awful to fix the unncessary pointer indirection (which looks like it's already happened), but I don't want 10x or even 2x longer compile times just because someone is trying to get the compiler to avoid boxing. It's a tradeoff, vs. e.g. spending that time simplifying methods to get the inliner to approve of them, which is win/win.

Re: Generics can make your Go code slower

#324
post #311

Earlier quoted context omitted.

Well, that is simply not true at all. Go is a perfectly capable replacement for Java and C#. Many huge projects that would likely never be written in Python have been written in Go when they would have otherwise been written in Java or C# in years past: Kubernetes, Prometheus, HashiCorp Vault and Terraform, etcd, CoreDNS, TiDB, Loki, InfluxDB, NATS, Docker, Caddy, Gitea, Drone CI, Faktory, etc. The list goes on and o…

golang doesn't have annotations, doesn't have enums, error handling is very error prone. No ability to choose from different GC implementations, nothing remotely close to JFR.

Go does have some of these features: annotations, enums, JFR. They're just built for features of Go rather than Java. They're not the same but perform similar roles for the Go language. Error handling is subjective but I'm not going to disagree it could use some help. Same with Go's GC in certain situations but nothing I've coded has needed more.

All that said, what makes your list any different than a similar list comparing Java to Blub? I don't see your list as preventing one from writing a Java app in Go using Go's idioms instead. (It can't fully do what Java or C# do.)

Re: Generics can make your Go code slower

#325

Earlier quoted context omitted.

I have a slightly contrary opinion. Systems software is a very large umbrella, and much under that umbrella is not encumbered by a garbage collector whatsoever. (To add insult to injury, the term's definition isn't even broadly agreed upon, similar to the definition of a "high-level language".) Yes, there are some systems applications where a GC can be a hindrance in practice, but these days I'm not even sure it's a…

The article is from a database company, so I'll assume that approximates the scope. My scope for the GC discussion would include other parts that could be considered similar software: cluster-control plane (Kubernetes), other databases, and possibly the first level of API services to implement a service like an internal users/profiles or auth endpoints. The tricky thing is GC works most of the time, but if you are wo…

As many have replied, the available levers for 'GC-tuning' in go is almost non-existent. However, what we do have influence on is "GC Pressure" which is a very important metric we can move in the right direction if the application requires it.

Re: Generics can make your Go code slower

#326

For me Go has replaced Node as my preferred backend language. The reason is because of the power of static binaries, the confidence that the code I write today can still run ten years from now, and the performance. The difference in the code I’m working with is being able to handle 250 req/s in node versus 50,000 req/s in Go without me doing any performance optimizations. From my understanding Go was written with dev…

Go was created with simplicity of feature set in mind, which does not translate into developer ergonomics automatically. It rather offers a least common denominator of lang features, so that most devs can handle it, who previously only handled other languages like Java and similar. This way Google aimed at attracting those devs. They'd not have to learn much to make the switch. True developer ergonomics, as far as a…

Rob Pike quantifies your sentiment as "Orthogonal Features"[0][1], which isn't necessarily equivalent to "simplicity of feature set". But I do understand what you meant.

I think in this context tho, developer ergonomics can mean different things to different people.

It's easy to see how "Orthogonal Features" can be interpreted as developer ergonomics, as its explicitly limiting potential (not all) anti-patterns and produces fairly idiomatic code across the ecosystem. I'm able to go to almost any Github repo that contains Go code, and easily determine whats going on, whats the flow, etc. Certainly ergonomic in that context.

[0]: https://go.dev/talks/2010/ExpressivenessOfGo-2010.pdf

[1]: https://www.informit.com/articles/article.aspx?p=1623555

Re: Generics can make your Go code slower

#327
post #95

This is a very interesting article. I was however a bit confused by the lingo, calling everything generics. As I understood it the main point of the article quite precisely matched the distinction between generics and templates as I learned it. Therefore what surprised me most was the fact that go monomorphizes generic code sometimes. Which however makes sense given the way go's module-system works – i.e. imported mo…

Rust also enthusiastically monomorphizes generic code. Templates vs generics seems to be more about the duck typing C++ templates use vs generics doing type parameters with statically checked constraints on the types.

Re: Generics can make your Go code slower

#328
post #311

Earlier quoted context omitted.

golang doesn't have annotations, doesn't have enums, error handling is very error prone. No ability to choose from different GC implementations, nothing remotely close to JFR.

Go does have some of these features: annotations, enums, JFR. They're just built for features of Go rather than Java. They're not the same but perform similar roles for the Go language. Error handling is subjective but I'm not going to disagree it could use some help. Same with Go's GC in certain situations but nothing I've coded has needed more. All that said, what makes your list any different than a similar list c…

> They're just built for features of Go

They're inferior, and do not cover the same grounds (e.g. "enums" in golang are just integer constants, you can't code gen using golang tags, JFR is way way more comprehensive than anything that golang has etc.)

The GC selection, JIT, and hot swapping/reloading are features that do not exist in golang, and we've seen what hoops people have to jump through when they face issues that can only be resolved by them. Basically, they're features most people don't know they need them until they do, then they'er already in a big mess.

You can write a Java app in golang or assembly, but it won't be anywhere near as maintainable, clear, concise, debuggable, or correct.

Re: Generics can make your Go code slower

#329

Earlier quoted context omitted.

> That said, compiling with Go 1.18 vs Go 1.17 got me a 10-15% speedup by itself. Where did you see this speedup? Other than `GOAMD64` there wasn't much in the release notes about compiler or stdlib performance improvements so I didn't rush to get 1.18-compiled binaries deployed, but maybe I should... (I do expect some nice speedups from using Cut and AvailableBuffer in a few places, but not without some rewrites.)

GOAMD64 could be significant, so I'm not sure why your comment seems to dismiss it? Also, as the article mentions, Go 1.18 can now inline functions that contain a "range" for loop, which previously was not allowed, and this would contribute performance improvements for some programs by itself. The new register-based calling convention was extended to ARM64, so if you're running Go on something like Graviton2 or an Ap…

> GOAMD64 could be significant, so I'm not sure why your comment seems to dismiss it?

Because it's not just upgrading from 1.17 to 1.18, you actually need to set it. Also because I ran a bunch of our code's benchmark suites, including a rather large set of custom serdes, and saw no improvements. Even some of the synthetic benchmarks used to introduce the new optimizations are below 10%.

Hopefully it'll grow in scope over the next few versions.

Re: Generics can make your Go code slower

#330
Monomorphisation is a double-edged blade. Sometimes keeping the code smaller and hot is better than inlining everything, especially when your application does not exclusively own all the system resources (an assumption that many “systems programming languages” sadly do). There is too much focus on “performance” aka. microbenchmarks, but they don’t tell you the whole story. If you have a heavily async environment, with multiple tasks running in parallel and waiting on each other in complex patterns, more compact, reusable code can not only speed up the work but also allow you to do more work per watt of energy.

I think it’s great that golang designers decided to follow Swift’s approach instead of specializing everything. The performance issues can be fixed in time with more tools (like monomorphissation directives) and profile-guided optimization.

Post reply on HN