怎么写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