Go言語における構造体のフィールドへのアクセス方法には、ドット(.)を使用した場合、次の二通りがあると思います。
go
1type Node struct { 2 id int 3} 4 5func main() { 6 n := Node{} 7 n.id = 0 8 9 m := &Node{} 10 m.id = 0 11}
この二つの方法の性能を測るベンチマークを次のコードで実行しました。
go
1package test 2 3import ( 4 "testing" 5) 6 7type Node struct { 8 id int 9} 10 11const C = 10000 12 13func BenchmarkA(b *testing.B) { 14 b.ResetTimer() 15 for i := 0; i < b.N; i++ { 16 n := Node{} 17 n.id = 0 18 } 19} 20 21func BenchmarkB(b *testing.B) { 22 b.ResetTimer() 23 for i := 0; i < b.N; i++ { 24 n := &Node{} 25 n.id = 0 26 } 27} 28
以下のような結果が出ました。数回計測しましたが、どれもほぼ同じ結果でした。(ns/opに0.01ほどの差)
$ go test -bench . -benchmem -gcflags '-N -l' goos: linux goarch: amd64 BenchmarkA-6 1000000000 0.993 ns/op 0 B/op 0 allocs/op BenchmarkB-6 801381580 1.49 ns/op 0 B/op 0 allocs/op
実体からフィールドにアクセスする場合とポインタからアクセスする場合で、なぜ速度が変わるのでしょうか?
次に、構造体そのものをスライスにappendする場合と構造体のポインタをappendする場合の差を調べるために、以下のコードでベンチマークを行いました。
go
1package test 2 3import "testing" 4 5type Node struct { 6 id int 7} 8 9const C = 10000 10 11func BenchmarkA(b *testing.B) { 12 b.ResetTimer() 13 for i := 0; i < b.N; i++ { 14 l := []Node{} 15 for j := 0; j < C; j++ { 16 n := Node{} 17 l = append(l, n) 18 } 19 } 20} 21 22func BenchmarkB(b *testing.B) { 23 b.ResetTimer() 24 for i := 0; i < b.N; i++ { 25 l := []*Node{} 26 for j := 0; j < C; j++ { 27 n := &Node{} 28 l = append(l, n) 29 } 30 } 31}
結果は以下のようになりました。
$ go test -bench . -benchmem -gcflags '-N -l' goos: linux goarch: amd64 BenchmarkA-6 22455 53447 ns/op 386301 B/op 20 allocs/op BenchmarkB-6 5648 192217 ns/op 466298 B/op 10020 allocs/op
ポインタをappendする方が、メモリ割り当て回数が非常に多くなっていて、実行時間も増えています。
どこでこのような差が生まれているのでしょうか?

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/08 00:42
2021/03/08 05:50
2021/03/08 08:40
2021/03/08 12:00
2021/03/08 12:13