Live data from Hacker News

Making a Go program faster with a one-character change

hmarr.com

121–130 of 249 posts

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

#121
post #33

Earlier quoted context omitted.

I also have a background in C/C++, etc and I've only ever found myself missing value semantics when I use languages with implicit reference semantics. I guess I always figured the solution was "value semantics with better education / tooling". Education: people should understand value semantics. Tooling: imagine an IDE that highlights allocation points automatically (or perhaps the problem is implicit allocations rat…

> I've only ever found myself missing value semantics when I use languages with implicit reference semantics. Oh, I miss it every time. ;-) I will say though that some newer languages seem to have a confused idea about how to offer mixed semantics. A bunch of them tie semantics to types. The ideal interface can vary by usage context. It's hard enough getting the semantics right as the callee (as opposed to caller), l…

> I will say though that some newer languages seem to have a confused idea about how to offer mixed semantics. A bunch of them tie semantics to types.

Curious about what you mean here. This sounds like C#'s class/struct distinction to me.

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

#122

Earlier quoted context omitted.

>In Rust you can write a function that returns the pointer of one element of a slice. Have fun fighting the borrow checker on that one.

It's not always so bad :) https://play.rust-lang.org/?version=stable&mode=debug&editio...

Now try to actually do that in a larger program without static lifetimes...

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

#123

Earlier quoted context omitted.

It's the difference between assigning/passing around "copies of the data" vs. assigning/passing around "the memory address for that data" under the hood. PHP, for example, has explicit references. If you have an `$arr1=array(1,2,3)` and an `$arr2 = $arr1`, that second array is a full copy of the first array, and updating $arr1 does nothing to $arr2. Similarly, `function update_array($arr) { $arr[0] = 'cake'; }` calle…

That's not technically correct with regards to PHP. Your statement that any changes to $arr1 or $arr2 only impact the one in question, however, is accurate. If no changes are made they still refer to the same data in memory. It's copy-on-write semantics. $arr1 = [1,2,3]; // $arr1 is a pointer to a zval array [1,2,3] and refcount:1 $arr2 = $arr1; // $arr1 and $arr2 are pointers to the same zval array but incremented r…

This isn't semantics, though, but implementation. As far as I'm aware there's no way to "observe" the copy short of digging into runtime debugging tools, so I think it's still fair to say the language has pass-by-value semantics. In C++ we still refer to things returned-by-value as returned by value despite the reality of NRVO, etc.

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

#124
post #8

Earlier quoted context omitted.

It would probably be more accurate to say it can do 70% more stuff in the same time. Or that it takes 42% less runtime

But 70% more stuff in the same time is 70% faster.

Let's say you do 10 things in 100 time (100/10 =10 time per thing) to start with:

70% more stuff in the same time is 17 things in 100 time (100/17 =5.9 time per thing);

70% faster is 10 things in 30 time (30/10 =3 time per thing) - or, I would argue incorrectly, perhaps said to mean 10 things in 70 time (70/10 =7 time per thing).

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

#125

There is potentially another option: use the midstack inliner to move the allocation from the heap to the stack of the calling function: https://words.filippo.io/efficient-go-apis-with-the-inliner/ As long as the global slice is never mutated, the current approach is probably fine, but it is definitely a semantic change to the code.

Why doesn't go use RVO like C++ and Rust?

https://en.wikipedia.org/wiki/Copy_elision#Background

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

#126

There is potentially another option: use the midstack inliner to move the allocation from the heap to the stack of the calling function: https://words.filippo.io/efficient-go-apis-with-the-inliner/ As long as the global slice is never mutated, the current approach is probably fine, but it is definitely a semantic change to the code.

Why doesn't go use RVO like C++ and Rust? https://en.wikipedia.org/wiki/Copy_elision#Background

I don’t think we’re on the same page about what midstack inlining is being used for in my suggestion. This discussion is about eliminating a heap allocation, which as far as I understand, RVO never does. Please read the article I linked if you want to discuss this further. I don’t want to repeat the article pointlessly.

I’m also fairly sure Go uses RVO here too, which cuts down on the number of times the object is copied around, but again, it’s irrelevant to the discussion of heap allocations. Copying the object isn’t the performance problem here, needlessly allocating a very short-lived object on the heap over and over is.

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

#128
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 unless you've got a specific reason for them. This applies even more so if you're creating a lot of pointers (like in a loop, or a function that gets called very frequently).

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

#129

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).

[deleted]

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

#130

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).

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)
Post reply on HN