概要
スライスに要素を追加するappendとインデックスを直接指定する方法のパフォーマンスが気になったので、ベンチマークテストの比較を行ってみた。
環境
- MacBook Air M1 メモリ16GB、go 1.23.0
計測方法
-
[]int
型のスライスに10,000,000回要素を追加する処理のベンチマークテストを実施
サンプルコード
package main
import "testing"
const size = 10000000
// ベンチマーク関数: append の場合
func BenchmarkAppend(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var slice []int
for j := 0; j < size; j++ {
slice = append(slice, j)
}
}
}
// ベンチマーク関数: slice[i] = int の場合
func BenchmarkIndexAssignment(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
slice := make([]int, size)
for j := 0; j < size; j++ {
slice[j] = j
}
}
}
計測結果
goos: darwin
goarch: arm64
pkg: performance
cpu: Apple M1
BenchmarkAppend-8 40 29059970 ns/op 492000713 B/op 51 allocs/op
BenchmarkIndexAssignment-8 264 4503033 ns/op 80003085 B/op 1 allocs/op
PASS
ok performance 3.679s
※ベンチマークテストでは内部で複数回の計測を実施しており、テストを数回実行しても結果のばらつきはほとんどなかったので1回分のみを記載
append(BenchmarkAppend-8)
- 実行回数: 40回
- 平均実行時間: 29,059,970 ns/op(約29.1ms/1回)
- メモリ使用量: 492,000,713 B/op(約492MB/1回)
- メモリアロケーション回数: 51回
インデックス指定(BenchmarkIndexAssignment-8)
- 実行回数: 264回
- 平均実行時間: 4,503,033 ns/op(約4.5ms/1回)
- メモリ使用量: 80,003,085 B/op(約80MB/1回)
- メモリアロケーション回数: 1回
比較
append | インデックス指定 | |
---|---|---|
実行回数 | 40回 | 264回 |
平均実行時間 | 29,059,970 ns/op(約29.1ms/1回) | 4,503,033 ns/op(約4.5ms/1回) |
メモリ使用量 | 492,000,713 B/op(約492MB/1回) | 80,003,085 B/op(約80MB/1回) |
メモリアロケーション回数 | 51回 | 1回 |
-
実行回数
-
インデックス指定
はappend
と比べて実行回数は 約6倍多い
-
-
実行時間
-
インデックス指定
はappend
と比べて実行速度が 約6倍速い
-
-
メモリ使用量
-
インデックス指定
はappend
の 約6分の1 のメモリ使用量
-
-
アロケーション回数:
-
インデックス指定
は最初に要素数分のメモリを確保するので 1回 のみ
-
結論
- 今回の計測方法ではインデックス指定の方が append より 実行速度、メモリ効率共に優れている結果となった
- データ量が少ないときはそこまで影響はないかもしれないが、スライスに要素を追加する際にあらかじめサイズが分かっている場合は、インデックスを指定する方法を使用するようにしたい