怎么写Go的基准测试
文章目录
Dave Cheney在他的blog写了一篇关于Go的基准测试编写的基本介绍(链接)。我以此为内容,整理输出内容。
对自己编写package编写基准测试是必不可少的过程,尤其对于执行性能有重要影响的代码,更是需要。Go向来是以工具丰富而著称的,从代码格式调整,到单元测试,到竞争检查,以及我们接下来要介绍的基准测试,都提供方便的工具给开发者。
我们以Fibonacci函数来介绍。
//fib.go
func Fib(n int) int {
	if n < 2 {
	    return n
	}
	return Fib(n-1) + Fib(n-2)
}
编写第一个benchmark testing:
//fib\_test.go
func BenchmarkFib10(b *testing.B) {
	// 执行b.N 次Fib函数
	for n := 0; n < b.N; n++ {
	    Fib(10)
	}
}
以下几点需要注意:
- 基准测试需要位于文件名为”{packagename}_test.go”的文件中,如这里的”fib_test.go”
- 需要引入“testing”包
- 基准测试函数需要以”Benchmark”为函数名的开头
- 基准函数会执行许多遍。b.N的没次执行都会自增长,直到工具认为统计数据已经满足基准测试输出的要求。
完成以上代码,我们就可以调用工具执行测试了:
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkFib10   2000000           835 ns/op
ok      test/fib    2.522s
注意:
- 以上结果的第一行和第二行结果是go test执行的结果。
- 与go test相似,-bench flag可接收一个有效的正则表达式来执行符合条件的测试函数。
同时,也轻易通过以下代码扩展,得到多个测试基准的结果:
func benchmarkFib(i int, b *testing.B) {
	for n := 0; n < b.N; n++ {
	    Fib(i)
	}
}
func BenchmarkFib1(b *testing.B)  { benchmarkFib(1, b) }
func BenchmarkFib2(b *testing.B)  { benchmarkFib(2, b) }
func BenchmarkFib3(b *testing.B)  { benchmarkFib(3, b) }
func BenchmarkFib10(b *testing.B) { benchmarkFib(10, b) }
func BenchmarkFib20(b *testing.B) { benchmarkFib(20, b) }
func BenchmarkFib40(b *testing.B) { benchmarkFib(40, b) }
运行结果:
BenchmarkFib1   500000000            7.81 ns/op
BenchmarkFib2   100000000           18.4 ns/op
BenchmarkFib3   100000000           24.9 ns/op
BenchmarkFib10   1000000          1269 ns/op
BenchmarkFib20     20000        109198 ns/op
BenchmarkFib40         1    1780678179 ns/op
ok      test/fib    14.852s
其他说明:
- 每个测试的运行最小运行时间默认是1s,如果测试返回结果时,运行时间还没达到1s,b.N将以1, 2, 5, 10, 20, 50, … 的序列递增,然后重新运行测试代码。 
- 注意上面的结果中,BenchmarkFib40只运行了一次,这是由于它的执行太慢。为了得到更大的样例数据,你可以通过设置最小运行时间来达到。设置-benchtime flag的即可。 - go test -bench=Fib40 -benchtime=10s PASS BenchmarkFib40 10 1711313264 ns/op ok test/fib 18.989s
特别注意: * 由于b.N是字增的,所以要谨慎用它来做函数参数。不要患下面这样的错误,否则,测试运行将没法终止。
func BenchmarkFibWrong(b *testing.B) {
	for n := 0; n < b.N; n++ {
	    Fib(n)
	}
}
func BenchmarkFibWrong2(b *testing.B) {
	Fib(b.N)
}
文章作者 justin huang
上次更新 2013-07-04