Live data from Hacker News

Generics can make your Go code slower

planetscale.com

161–170 of 418 posts

Re: Generics can make your Go code slower

#161
post #133

Earlier quoted context omitted.

I think you're mistaken on nearly every count. :) First of all, Go and Java exist at roughly the same performance tier. It will be less work to make Java beat Go for some applications and vice versa for other applications. Moreover, typical Go programs use quite a lot less memory than typical Java programs (i.e., there's more than one kind of performance). Secondly, Go can make syscalls directly, so it absolutely can…

I disagree. Go is definitely not as fast as Java for throughput. It's gotten pretty good for latency sensitive workloads but it's simply left in the dust for straight throughput, especially if you are hammering the GC. Sure it can make syscalls directly but if you are going to talk about a maintainability nightmare I can't think of anything worse than trying to manipulate threads directly in Go. I had to do this in a…

I think your use of “subjective” is avoiding discussing things that are harder to prove but matter a great deal.

Re: Generics can make your Go code slower

#162
post #20

Earlier quoted context omitted.

I don't know about you, but when I imagine what compilers do with generic code, I typically imagine monomorphization, which (aside from increasing cache pressure a little), should generally not make things slower, but rather introduce possibilities for inlining that could make it faster.

Apparently I scrolled right past that bit of the article. I’m a little unsure how it’s suppose to make the code faster, but maybe because I compare it wrong. The alternative to generics is writing all the different function by hand, in my mind at least. I don’t fully understand how generics are suppose to be made faster than a custom function for that datatype.

> I don’t fully understand how generics are suppose to be made faster than a custom function for that datatype.

The point is that a monomorphized generic function should not be slower than the custom-function-per-datatype, but because Go's generics are not fully monomorphized they can be, and in fact can be slower than the a function-for-interface.

Re: Generics can make your Go code slower

#163

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…

> What, exactly, are you saying that Go can't do that Java can? Runtime library addition (plugins) and dependency injection are two big ones. (We can argue the merit separately, but they're not possible in Go) I think if Java had easily distributable static binaries k8s would have stayed Java (it started out as Java).

> Runtime library addition (plugins)

I don't see anything inherit to Go that would prevent it. gc even added rudimentary support some time ago, fostering the addition of the plugin package[1], but those doing the work ultimately determined that it wasn't useful enough to dedicate further effort towards improving it.

There was a proposal to remove it, but it turns out that some people are using runtime library addition, and so it remains.

[1] https://pkg.go.dev/plugin

Re: Generics can make your Go code slower

#164
post #92

Earlier quoted context omitted.

You're definitely right. While it's not a particularly common problem, it does exist; one thing I'd really like to see enter the compiler world is an optimization step to use vtable dispatch (or something akin to Rust's enum_dispatch, since all concrete types should be knowable at compile time) in these cases. I expect it would require a fair amount of tuning to become useful, but could be based on something analogou…

enum dispatch in Rust is one of my favorite tricks. Most of the time you have a limited number of implementations, and enum dispatch is often more performant and even less limiting (than say trait objects)

I'm a huge fan. It's very little work to use, as long as all variants can be known to the author, and as long as you aren't in a situation where uncommon variants drastically inflate the size of your common variants, it's a performance win, often a big one, compared to a boxed trait object.

Even when you have to box a variant to avoid inflating the size of the whole enum, that's still an improvement over a `dyn Trait` - it involves half as much pointer chasing

It'd be cool to see this added as a compiler optimization - even for cases where the author of an interface can't possibly know all variants (e.g. you have a `pub fn` that accepts a `&dyn MyTrait`), the compiler can

Re: Generics can make your Go code slower

#165

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…

> A good portion of production outages are likely related to cascading failures due to too long GC pauses, and a good portion of developer time is spent testing and tuning GC parameters.

Can’t really accept that without some kind of quantitative evidence.

Re: Generics can make your Go code slower

#166

Earlier quoted context omitted.

Rust itself will most likely get some form of support for local, "pluggable" garbage collection in the near future. It's needed for managing general graphs with possible cycles, which might come up even in "systems programming" scenarios where performance is a focus - especially as the need for auto-managing large, complex systems increases.

`Rc` and `Arc` have weak references which have worked just fine for me to break cycles in a graph. Not saying my use case is the most complex, but I haven't noticed this as a problem yet. YMMV

If your data is "mostly a tree but has the occasional back reference I can easily identify as a back reference", that works great and I've used it in other languages.

But in the limit, as your data becomes maximally "graphy" and there isn't much you can do about it, this ceases to be a viable option. You have to be able to carve a "canonical tree" out of your graph for this to work and that's not always possible. (Practically so, I mean. Mathematically you can always define a tree, by simple fiat if nothing else, but that doesn't help if the only available definitions are not themselves practical.)

Re: Generics can make your Go code slower

#167

Earlier quoted context omitted.

`Rc` and `Arc` have weak references which have worked just fine for me to break cycles in a graph. Not saying my use case is the most complex, but I haven't noticed this as a problem yet. YMMV

But the whole point of weak references is that they don't get shared ownership (i.e. extend the lifetime) of their referenced values. That's not doing GC. They're fine when there's always some other (strong) reference that will ensure whatever lifetime is needed, but that's not the general case that GC is intended for.

Weak pointers don't create a strong reference, correct, and that is exactly what is needed to break a cycle. Since it is a cycle, there is some other "owning" strong reference out there. Every use case I've seen generally has an obvious strong and weak reference (usually parent vs child). I'm sure there are trickier corner cases, but that is the typical IMO.

For everything else, Rust has no need for a tracing GC, as it has "compile time" GC via static lifetime analysis which is much better IMO already and often avoid heap allocation all together.

Re: Generics can make your Go code slower

#168
post #166

Earlier quoted context omitted.

`Rc` and `Arc` have weak references which have worked just fine for me to break cycles in a graph. Not saying my use case is the most complex, but I haven't noticed this as a problem yet. YMMV

If your data is "mostly a tree but has the occasional back reference I can easily identify as a back reference", that works great and I've used it in other languages. But in the limit, as your data becomes maximally "graphy" and there isn't much you can do about it, this ceases to be a viable option. You have to be able to carve a "canonical tree" out of your graph for this to work and that's not always possible. (Pr…

Fair point - so far I've been lucky enough to avoid such use cases

Re: Generics can make your Go code slower

#169

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…

> The tricky thing is GC works most of the time, but if you are working at scale you really can't predict user behavior, and so all of those GC-tuning parameters that were set six months ago no longer work properly. A good portion of production outages are likely related to cascading failures due to too long GC pauses, and a good portion of developer time is spent testing and tuning GC parameters. It is easier to remove and/or just not allow GC languages at these levels in the first place.

Getting rid of the GC doesn't absolve you of the problem, it just means that rather than tuning GC parameters, you've encoded usage assumptions in thousands of places scattered throughout your code base.

Re: Generics can make your Go code slower

#170

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…

> What, exactly, are you saying that Go can't do that Java can? Runtime library addition (plugins) and dependency injection are two big ones. (We can argue the merit separately, but they're not possible in Go) I think if Java had easily distributable static binaries k8s would have stayed Java (it started out as Java).

I believe Go supports DI via Wire (https://github.com/google/wire).
Post reply on HN