Golangでベンチマークを取ってみた

Golangでどんな書き方をするのがいいのかパフォーマンスを指標にしてみよう!ということでベンチマークを取ってみました。


やり方

*_test.goでファイルを作成します。

今回は文字列連結のパフォーマンス計測がしたいので以下の感じのコードを書きます。

package main

import "testing"

func BenchmarkMemAllocBeforeCustom(b *testing.B) {
n := 10
b.ResetTimer()
for i := 0; i < b.N; i++ {
s := ""
for j := 0; j < n; j++ {
s = s + "alice"
}
}
}

func BenchmarkMemAllocCustom(b *testing.B) {
n := 10
b.ResetTimer()
for i := 0; i < b.N; i++ {
s := make([]byte, 0)
for j := 0; j < n; j++ {
s = append(s, "alice"...)
}
}
}


ベンチマークの実行

ベンチマークの実行は以下のコマンドで行います。

$ go test -bench .

PASS
BenchmarkMemAllocBeforeCustom-4 2000000 815 ns/op
BenchmarkMemAllocCustom-4 5000000 373 ns/op
ok bench-test 4.669s

他にもオプションつけたりできます。

$ go test -bench . -benchmem

PASS
BenchmarkMemAllocBeforeCustom-4 2000000 815 ns/op 336 B/op 9 allocs/op
BenchmarkMemAllocCustom-4 5000000 373 ns/op 120 B/op 4 allocs/op
ok bench-test 4.669s

なんか謎の数値が並んでますが、-benchmemの結果を簡単に説明すると以下な感じです。

// 関数の実行回数、有用な結果が得られるまで実行される

// 多ければ多いほど良い
2000000

// 1回の実行にかかった時間
// 少ないほど良い
815 ns/op

// 実行ごとに割り当てられたメモリのサイズ
// 少ないほど良い
336 B/op

// 1回の実行でメモリアロケーションが行われた回数
// 少ないほど良い
9 allocs/op

ベンチマークの結果の見方が分からなくなったらこの辺のBenchmarkStructに意味が書いてあるっぽいので読みましょう。

https://github.com/golang/tools/blob/master/benchmark/parse/parse.go#L28-L37

[追記:2019/02/27]

Go1.12になったことでちょこっと変更が加わりました。

https://syossan.hateblo.jp/entry/2019/02/27/171156


参考

Go でベンチマーク

go test で出来ること

Goでは文字列連結はコストの高い操作