Live data from Hacker News

Making a Go program faster with a one-character change

hmarr.com

141–150 of 249 posts

Re: Making a Go program faster with a one-character change

#141

The deeper lesson here is "don't use pointers unless you're sure you need them". I've seen quite a few people use pointers for no reason in particular, or there's simply the assumption it's faster (and have done this myself, too), but it puts a lot more pressure on the GC than simple local stack variables. Of course sometimes pointers are faster, or much more convenient. But as a rule of thumb: don't use pointers unl…

That's not a deeper lesson. A deeper lesson is to understand where the pointer points to and then decide accordingly.

Re: Making a Go program faster with a one-character change

#142

Earlier quoted context omitted.

Agreed. Could you Imagine a Java where you have a `Map` and a `MutableMap` and that's what you put at your API? I'd make it SO much clearer how safe any individual API is to call.

In general this doesn't work, the history rule says mutable types are not proper subtypes of immutable ones (and the converse is obvious). If you want to capture mutability in your type system, it needs to be orthogonal to subtyping (like C/C++ const).

> the history rule

I'm unfamiliar with this rule (and not finding anything good to google). Can you elaborate?

I can't really think of a scenario where an immutable datastructure isn't a subset of actions against a mutable datastructure.

Re: Making a Go program faster with a one-character change

#143

Would be interesting to see the performance difference if you undo that move-&-change and change the function signature from: func (r Ruleset) Match(path string) (*Rule, error) to: func (r *Ruleset) Match(path string) (*Rule, error)

Likely none: Ruleset is

    type Ruleset []Rule
The original code creates a local copy of a rule and explicitly returns a pointer to that. Taking the ruleset by address wouldn't change that issue.

Re: Making a Go program faster with a one-character change

#144

Earlier quoted context omitted.

Java has been tunable for a long time. Periodically, the recommended tuning changes, or new GC algorithms become available, etc. But it has long been possible to get short pause times with various combinations of choosing the right algorithm and writing your program the right way. I think what really throws people off here is that getting good performance out of a Java application involves some skills which are alien…

Agreed, but usually tuning for short pause times involves trading off throughput or allocation performance. But at the end of the day, if you aren't allocating a bunch of garbage in the first place, then you don't need to be as concerned about the costs of allocating or cleaning up the garbage. I wish Go did more to make allocations explicit so they could be more easily recognized and avoided; I dislike Java's approa…

What do you consider a ‘long’ pause time?

I’ve had no issues with Java 17+ under heavy allocation/garbage collection (data encryption pipeline I haven’t tuned to reuse buffers yet), and it’s pause times are on the order of a handful of milliseconds, without meaningful tuning. I think it’s doing something like a GB/s of garbage collection.

And the jvm in question is doing a LOT more than just this, so it’s coping with millions of allocated objects at the same time.

Re: Making a Go program faster with a one-character change

#145
post #130

Earlier quoted context omitted.

C++ still has this problem - std::unordered_map ` and `std::unordered_map ` are basically unrelated types - you can't const-cast the templated const away. (I may be misunderstanding here)

> you can't const-cast the templated const away. That seems like a good thing. If you're handed a map to const values you can't just go "imma gunna mutate them anyway".

Normally (when containers are not involved) this is exactly the point of a const cast.

Re: Making a Go program faster with a one-character change

#146
post #96

Earlier quoted context omitted.

> When I write code, it's common to have references to immutable classes thrown around with wild abandon, heedless of ownership, threads, or good taste, because the data just can't change. If there's anything I wish languages with implicit reference semantics would adopt, it's implicit immutability. I wish Java would be so much nicer with keyword that is half way between "final" and "volatile" that means, "yes, you c…

Agreed. Could you Imagine a Java where you have a `Map` and a `MutableMap` and that's what you put at your API? I'd make it SO much clearer how safe any individual API is to call.

Scala has had this for ages. You can have it today. Even in Java either through the Google collection library or through a library that mimics fp style programming. The name eludes me for the moment.

Re: Making a Go program faster with a one-character change

#147
> If you read the title and thought “well, you were probably just doing something silly beforehand”, you’re right!

Don't feel too silly. Russ Cox, one of the technical leads on the Go language, made the same mistake in the regexp package of the standard library.

https://go-review.googlesource.com/c/go/+/355789

Re: Making a Go program faster with a one-character change

#148
post #6

Went from 4.139s to 2.413s. I fail to see how it is 70%. I think it is explained as 4.139/2.413 = 1.7 which of course doesn't make sense here.

I do think saying it's 71% faster makes sense here, since "x% faster" and "speed increased by x%" mean the same thing. This reduces the runtime by 42%, but that doesn't mean it's just 42% faster.

Re: Making a Go program faster with a one-character change

#149
post #21

As an old C/C++ programmer, I'm always surprised by how often software developers are surprised by the performance costs of inopportune value semantics (C and C++ even more so, punishes you severely for using value semantics when you shouldn't). I increasingly see the wisdom of languages with implicit reference semantics. It's not that value semantics can't be better (they most assuredly can be), or that reference se…

I'm a dumb dumb. Can you define "implicit reference semantics" and "value semantics"? You use the phrases several times in your post, but I don't really understand what you mean. If it helps, I'm not a C++ programmer, but I am familiar with higher level languages like Go, Python, Ruby, PHP and Javascript.

Thank you for asking - I, too, was a dumb dumb.

Re: Making a Go program faster with a one-character change

#150
post #29

Overall good review of profiling tactics . But there’s nothing egregious about Golang here . Pass by value vs reference is a common performance issue.

> But there’s nothing egregious about Golang here . Pass by value vs reference is a common performance issue.

The trap here is that everything is passed by reference (pointer), but the intermediate local value is, well, a value (a copy).

Rule is not a gigantic monster struct (it's 72 bytes), chances are returning it by value would not have been an issue.

Anyway I would say there is an issue with Go here: it's way too easy to copy out of a slice.

Post reply on HN