3 ms·
EDIT: I think the use of the term "allocation" might be overloaded here from the original article, after thinking about this a bit more I think the author is re
by djhworld 4y ago
EDIT: I think the use of the term "allocation" might be overloaded here from the original article, after thinking about this a bit more I think the author is referring to a different way of accessing the map. If you look in godbolt https://godbolt.org/z/Yf64rodW6 https://godbolt.org/z/Yf64rodW6 you can see that the pointer version uses
CALL runtime.mapaccess2_fast64(SB)
whereas the 'raw' version uses
CALL runtime.mapassign_fast64(SB)
When reading the Go solution this bit stood out to me
> To reduce the allocations, we’ll use a map[string]*int instead of map[string]int so we only have to allocate once per unique word, instead of for every increment
I just tried benchmarking this with a simple setup and I get zero allocations for both approaches, although the "pointer" approach is slightly faster
package main
import (
"testing"
)
func BenchmarkIncrementMapRawInt(b *testing.B) {
var data = make(map[int]int)
b.ResetTimer()
for i := 0; i < b.N; i++ {
key := i % 1000
data[key]++
}
}
func BenchmarkIncrementMapPointerInt(b *testing.B) {
var data = make(map[int]*int)
b.ResetTimer()
for i := 0; i < b.N; i++ {
key := i % 1000
increment(data, key)
}
}
func increment(counts map[int]*int, value int) {
if p, ok := counts[value]; ok {
*p++
return
}
n := 1
counts[value] = &n
}
$ go test -bench=. -benchmem .
goos: darwin
goarch: arm64
BenchmarkIncrementMapRawInt-8 112288002 10.57 ns/op 0 B/op 0 allocs/op
BenchmarkIncrementMapPointerInt-8 139728302 8.586 ns/op 0 B/op 0 allocs/op
- dan-robertson 4y agoPresumably this would allocate if bits weren’t “primitive”, eg if you had 128 bit ints implemented as a tuple of two ints.