Live data from Hacker News

Generics can make your Go code slower

planetscale.com

71–80 of 418 posts

Re: Generics can make your Go code slower

#71
post #62
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…

Typical gatekeeping. I like Go, because it lets me get stuff done. You could say the same about JavaScript, but I think Go is better because of the type system. C, C++ and Rust are faster in many cases, but man are they awful to work with. C and C++ dont really have package management to speak of, its basically "figure it out yourself". I tried Rust a couple of times, but the Result/Option paradigm basically forces y…

> C and C++ dont really have package management to speak of

I hear this complaint often, but I consider it a feature of C. You end up with much less third party dependencies, and the libraries you do end up using have been battle tested for decades. I much prefer that to having to install hundreds of packages just to check if a number is even, like in JS.

Re: Generics can make your Go code slower

#72
post #62
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…

Typical gatekeeping. I like Go, because it lets me get stuff done. You could say the same about JavaScript, but I think Go is better because of the type system. C, C++ and Rust are faster in many cases, but man are they awful to work with. C and C++ dont really have package management to speak of, its basically "figure it out yourself". I tried Rust a couple of times, but the Result/Option paradigm basically forces y…

I've found Go to be much simpler than Rust, especially syntax wise. However, in Rust you can use the ? operator which propagates errors. In Go you have to check err != nil.

Re: Generics can make your Go code slower

#73
post #3

Reading the title I'm worried, should I keep using reflection instead?

Definitely not. In the general case, you will make things simpler and faster by turning reflection-based code into generic code.

What this article says is that a function that is generic on an interface introduces a tiny bit of reflection (as little as is necessary to figure out if a type conforms to an interface and get an itab out of it), and that tiny bit of reflection is quite expensive. This means two things.

One, if you're not in a position where you're worried about what does or does not get devirtualized and inlined, this isn't a problem for you. If you're using reflection at all, this definitely doesn't apply to you.

Two, reflection is crazy expensive, and the whole point of the article is that the introduction of that tiny bit of reflection can make function calls literally twice as slow. If you are in a position where you care about the performance of function calls, you're never really going to improve upon the situation by piling on even more reflection.

Re: Generics can make your Go code slower

#74

This is a really long and informative article, but I would propose a change to the title here, since "Generics can make your Go code slower" seems like the expected outcome, where the conclusion of the article leans more towards "Generics don't always make your code slower", as well as enumerating some good ways to use generics, as well as some anti-patterns.

In C++, generics (templates) are zero-cost abstractions. So no, generics do not de facto make code slower.

There are no true zero cost abstractions under all situations. In the general case they make things faster, but I've personally made C++ code faster by un templating code to relieve I$ pressure, and also allow the compiler to make smarter optimizations when it has less code to deal with. The optimizer passes practically have a finite window they can look at because of the complexity class of a lot of optimizer algorithms.

Re: Generics can make your Go code slower

#75
Similar to how the GC has become faster and faster with each version, we can expect the generics implementation to be too. I wouldn’t pay much attention to conclusions about performance from the initial release of the feature. The Go team is quiet open with their approach.

Re: Generics can make your Go code slower

#76
post #62
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…

Typical gatekeeping. I like Go, because it lets me get stuff done. You could say the same about JavaScript, but I think Go is better because of the type system. C, C++ and Rust are faster in many cases, but man are they awful to work with. C and C++ dont really have package management to speak of, its basically "figure it out yourself". I tried Rust a couple of times, but the Result/Option paradigm basically forces y…

Nobody's saying you can't use Go or must use C/C++/Rust. If Go works for you, that's great.

The issue is about positioning of Go as a language. It's confusing due to being (formerly) marketed as a "systems programming language" that is typically a domain of C/C++/Rust, but technically Go fits closer to capabilities of Java or TypeScript.

Re: Generics can make your Go code slower

#77

This is a really long and informative article, but I would propose a change to the title here, since "Generics can make your Go code slower" seems like the expected outcome, where the conclusion of the article leans more towards "Generics don't always make your code slower", as well as enumerating some good ways to use generics, as well as some anti-patterns.

In C++, generics (templates) are zero-cost abstractions. So no, generics do not de facto make code slower.

C++ can suffer from negative performance from template bloat in two ways:

Templated symbol names are gigantic. This can impact program link and load times significantly in addition to the inflated binary size.

Duplication of identical code for every type, for example the methods of std::vector and std::vector should compile to the same instructions. There are linker flags that allow some deduplication but those have their own drawbacks, another trick is to actively use void pointers for code parts that do not need to know the type, allowing them to be reused behind a type safe template based API.

Re: Generics can make your Go code slower

#78
post #71
post #62

Earlier quoted context omitted.

Typical gatekeeping. I like Go, because it lets me get stuff done. You could say the same about JavaScript, but I think Go is better because of the type system. C, C++ and Rust are faster in many cases, but man are they awful to work with. C and C++ dont really have package management to speak of, its basically "figure it out yourself". I tried Rust a couple of times, but the Result/Option paradigm basically forces y…

> C and C++ dont really have package management to speak of I hear this complaint often, but I consider it a feature of C. You end up with much less third party dependencies, and the libraries you do end up using have been battle tested for decades. I much prefer that to having to install hundreds of packages just to check if a number is even, like in JS.

Hmm yes, why stop there? Why have functions? Just reimplement business logic all over your codebase. That way each block of code has everything you need to know. Sure, functions have been adopted by every other language/ecosystem and are universally known to be useful despite a few downsides but you could say the same about package management and that hasn't deterred you yet.

Re: Generics can make your Go code slower

#79
post #58

Earlier quoted context omitted.

this has been argued ad nauseum a decade ago and it boils down to your definition of 'systems'. at google scale, a system is a mesh of networked programs, not a kernel or low-level bit-banging tool.

By that definition, Java is a systems language as well. I think Go makes a better trade-off than Java, but I struggle to come up with decent examples of projects one could write in Go and not in Java. Most of the “systems” problems that Java is unsuitable for, also apply to Go.

Go is strictly less useful than Java because it has strictly less power. This is true for general purpose programming (though somewhat remediated through introduction of generics) it's doubly true for "systems" applications:

No access to raw threads. No ability to allocate/utilize off-heap memory (without CGo and nonsense atleast). Low throughput compared to Java JIT (unsuitable for CPU intensive tasks).

The only thing I can think of in it's favor is lower memory usage by default but this is mostly just a JVM misconception, you can totally tune it for low memory usage (in constrained env) or high memory efficiency - especially if using off-heap structures.

On a stdlib level Java mostly wins but Go has some highlights, it has an absolutely rock solid and well built HTTP and TLS/X.509/ASN1 stack for instance, also more batteries vs Java.

Overall I think if the requirement is "goes fast" I will always choose Java.

I may pick Go if the brief calls for something like a lightweight network proxy that should be I/O bound rather than CPU bound and everything I need is in stdlib and I don't need any fancy collections etc.

Re: Generics can make your Go code slower

#80
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.

The point is they shouldn't be slower than a manually-copied implementation for that concrete type. They also should be faster than vtable dynamic dispatch in the vast majority of cases. (I also fail to see a compelling reason that they couldn't have been implemented by passing the fat pointer directly, making the codegen the same as passing an interface, instead of having that business with the extra layer of indirection.)

If there are specialization opportunities when hand-implementing the function for a given concrete type, I would indeed expect that to be faster than a monomorphized generic function.

Post reply on HN