Goで構造体slice
Goの構造体sliceはいつもポインタで定義していましたが、
要素追加の時毎回allocationが走るので初期化時に構造体のsliceにした方がパフォーマンス的に良いそうです。
package main
import (
"strconv"
"testing"
)
type human struct {
age int
name string
}
func BenchmarkPointerSlice(b *testing.B) {
// 初期化時にslice分のメモリ容量を確保している
people := make([]*human, 0, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
people = append(people, &human{
age: i,
name: strconv.Itoa(i),
})
}
}
func BenchmarkSlice(b *testing.B) {
// ポインタ分の容量のみ確保している
people := make([]human, 0, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
// ここで毎回allocate
people = append(people, human{
age: i,
name: strconv.Itoa(i),
})
}
}
検証結果
~/.ghq/github.com/0daryo/playground go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: github.com/0daryo/playground
BenchmarkPointerSlice-8 15123596 77.8 ns/op 39 B/op 1 allocs/op
BenchmarkSlice-8 46061704 28.7 ns/op 7 B/op 0 allocs/op
PASS
ok github.com/0daryo/playground 3.471s
go test -bench . -benchmem 4.58s user 0.91s system 148% cpu 3.693 total
確かに実体の配列の方が3倍くらい速くてメモリ効率も良い
構造体のコピーコスト < allocation回数のコストだということだと思うのですが、オブジェクトサイズがあまりにも大きい場合はまた別問題かもしれません。