知识点:
- benchmark函数以
Benchmark
开头而非Test
开头. - 通过为
go test
命令添加-bench
标记的方式运行benchmark测试,参数的值是一个正则表达式,如果运行全部benchmark测试,则指定为-bench=.
即可; - 为了避免普通的测试case被执行,可以加上
-run=^$
(匹配空函数)来跳过执行; - 如果希望同步观察内存使用,可以通过
-benchmem
标记位来实现; - 为了确保结果的一致性,可以加上
-count
参数来重复运行benchmark; - 每个benchmark默认情况下会运行至少一分钟,我们可以通过
-benchtime
标记位来生成一个更准确的结果; -
b.N
的值会以1, 2, 5, 10, 20, 50, …这样的规律递增下去直到运行时间超过或等于1秒钟(可以通过上面的-benchtime
修改),这里不是时间一到就截止,运行期还会综合运行时间的稳定性来判断是否继续; - 接上一条,由于程序判断运行时间稳定才会停止运行,所以千万不要在loop循环里面使用一个变化的值作为函数的参数,这里要注意
b.N
是也是一个动态变化的值!
例子:
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 1000000000 2.84 ns/op
BenchmarkFib2 500000000 7.92 ns/op
BenchmarkFib3 100000000 13.0 ns/op
BenchmarkFib10 5000000 447 ns/op
BenchmarkFib20 50000 55668 ns/op
BenchmarkFib40 2 942888676 ns/op
说明:
- 第一列是执行的函数名称,第二列是总的执行次数,第三列是平均运行时间;
引申:
上面也可以用table driven的方式来运行多个case,这里类似于t.Run
方法,需要使用 b.Run
方法来执行多个case比如:
func BenchmarkFib(b *testing.B) {
var table = []struct {
input int
}{
{input: 10},
{input: 20},
{input: 50},
{input: 100},
}
for _, v := range table {
b.Run(fmt.Sprintf("input_size_%d", v.input), func(b *testing.B) {
for i := 0; i < b.N; i++ {
uniquePaths(v.input, v.input)
}
})
}
}
网友评论