什么是基准测试
基准测试是测试代码的一种方法,主要是通过测试代码CPU使用时间和内存占用率来评估被测试代码的性能,根据基准测试的结果来对代码进行优化从而达到期望的性能。
如何编写基准测试
itoa_test.go
func BenchmarkSprintf(b *testing.B){
num:=10
b.ResetTimer()
for i:=0;i<b.N;i++{
fmt.Sprintf("%d",num)
}
}
这是一个基准测试的例子,从例子可以看出:
1.代码必须以_test.go结尾
2.基准测试函数必须以Benchmark开头,并且方法必须接受testing.B指针类型作为唯一参数
3.基准测试函数不能够有返回值
4.b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰
5.测试的代码必须放在for循环内,for循环的次数b.N是由基准测试对象b提供的
执行命令
go test . -bench=.
输出结果:
BenchmarkSprintf-8 20000000 100 ns/op
第一列显示的是 方法名-cpuCoreNum,第二列是循环次数,第三列是平均耗时。
上面输出显示我的机器CPU是8核,总共执行了20000000次,每次操作平均耗时 100 ns。
测试执行时间默认是1秒,如果需要改变测试执行时间,比如指定执行时间2s,则可以通过以下命令:
go test . -bench=. -benchtime=2s
性能测试对比
上面那个基准测试的例子,其实是一个int类型转为string类型的例子,标准库里还有几种方法,我们看下哪种性能更加。
执行命令: go test . -bench=.
func BenchmarkSprintf(b *testing.B){
num:=10
b.ResetTimer()
for i:=0;i<b.N;i++{
fmt.Sprintf("%d",num)
}
}
func BenchmarkFormat(b *testing.B){
num:=int64(10)
b.ResetTimer()
for i:=0;i<b.N;i++{
strconv.FormatInt(num,10)
}
}
func BenchmarkItoa(b *testing.B){
num:=10
b.ResetTimer()
for i:=0;i<b.N;i++{
strconv.Itoa(num)
}
}
运行基准测试,查看输出结果:
BenchmarkSprintf-8 20000000 109 ns/op
BenchmarkFormat-8 300000000 4.11 ns/op
BenchmarkItoa-8 300000000 4.10 ns/op
根据结果可以看到Sprintf方法耗时最高,比其他两个方法慢了很多,另外两个耗时差不多。那么为什么这么慢呢,我们可以打印内存分配次数来查看原因。
执行命令:
go test . -bench=. -benchmem
查看结果:
BenchmarkSprintf-8 20000000 110 ns/op 16 B/op 2 allocs/op
BenchmarkFormat-8 300000000 4.07 ns/op 0 B/op 0 allocs/op
BenchmarkItoa-8 300000000 4.12 ns/op 0 B/op 0 allocs/op
原来Sprintf方式每次操作需要分配两次内存动作,每次分配16字节,而另外两种方式不需要内存分配动作,所以快很多。
总结
Go语言提供原生的基准测试方式,通过基准测试我们可以很方便的测试程序的性能,查看内存的分配次数,根据基准测试结果我们可以针对性的优化我们的程序性能。
参考文章:
https://www.flysnow.org/2017/05/21/go-in-action-go-benchmark-test.html