3 ms·
> You can sometimes use unnatural programming patterns in both Go and Java to reduce allocations in practice. This whole "you can't control your allocations in
by camgunz 7y ago
> You can sometimes use unnatural programming patterns in both Go and Java to reduce allocations in practice.
This whole "you can't control your allocations in Go" thing is a strawman. You don't have absolute control because of escape analysis, that's true. But there's a pretty wide gap between "oh I'll just move this allocation point out of a loop" and "oh I wrote a bunch of unnatural code". It's pretty idiomatic to manage allocations in Go, just look at all the posts about using pprof.
Besides, the spectrum of "clarity" (or whatever) to performance is present no matter what language you're using. Ex: ripgrep takes on more complexity so it can search a big buffer of text instead of just a line [1]. I wouldn't call that "unnatural" at all, just systems programming.
[1]: https://blog.burntsushi.net/ripgrep/#mechanics https://blog.burntsushi.net/ripgrep/#mechanics
- pcwalton 7y ago> But there's a pretty wide gap between "oh I'll just move this allocation point out of a loop" and "oh I wrote a bunch of unnatural code". Here's just one example: The Go compiler judges that parameters to indirect calls such as interface method calls as escaping. So in Go if you don't want to allocate you have no choice other than to avoid interfaces. But Go heavily encourages the use of interfaces, especially in the standard library. In C, C++, and Rust, on the other hand, you can use indirect calls without allocating, because the language guarantees the escaping behavior. This is a significant difference.
- smarterclayton 7y agoMy experience in the Golang side of this is limited to profiling and optimizing Kubernetes, which doesn't have extensive use of interfaces in general, but over the last 5 years I would say 90% of the wins we have have been: 1. optimizing allocations away in serialization 2. optimizing allocations away in api or biz logic in critical paths around that 3. algorithmic improvements on certain naive code paths 4. blocking ... distant gap 5. everything else Serialization is its own can of worms in Go, and many places we tried to optimize came down to trying to avoid a) stupid (don't use pointers to naive objects) and b) obvious (use value types) and then hit a wall where there weren't many cheap wins. I probably can count on one hand the number of hot paths which were interface related, so while I've occasionally been annoyed at the forced allocation moving into an interface, it's rarely actual something I've gotten a win from. That's just one particular experience, but the AMAZING integration with pprof from very early days has saved me far more time in improving perf than other Go annoyances has cost (relative to my experience in Java 2005-2011).
- camgunz 7y agoOh yeah, totally agree that you have way more control in C/C++/Rust, and that's non-negotiable in many important cases. I just don't think that's the same as "you don't have any meaningful control over allocations in Go"; you still have a lot of control. It's a spectrum, and if you don't do enough research you might find you need more control (you used Go) or you might also find you signed up to deal with more low-level memory management than you needed to (C/C++/Rust).