GO语言使用基准测试辅助进行代码调优
本部分内容建立在Centos7虚拟机的GO开发环境下,可能会由于外在因素导致性能测试不标准/不一,但总体使用基准测试来辅助进行代码调优的思想可以进行参考。
基准测试相关概念
- 基准测试利用了testing包
- 基准测试函数可以编写在以_test.go结尾的文件中,可以与test函数共存
- 基准测试接收的参数是
*testing.B
,相反单元测试使用的是*testing.T
- 运行基准测试,需要使用
-bench
标识,如果要运行运行包中的所有基准测试,使用-bench=.
- go test会先运行包中所有的单元测试,再进行基准测试,可以通过
go test -run=^$
让单元测试不执行。 - 基准测试一直调用b.N直到无效(从1开始,如果基准测试函数可以在1秒内完成,则再次运行基准测试)
编写一个简单的基准测试
实现一个简单的斐波那契数列求值函数,并编写基准测试代码
fib.go
package fib
func fib(n int) int {
switch n {
case 0: return 0
case 1: return 1
default: return fib(n-1)+fib(n-2);
}
}
fib_test.go
package fib
import "testing"
func BenchmarkFib(b *testing.B) {
for i:=0; i<b.N; i++ {
fib(40); // run fib(40) func for b.N times
}
}
结果如下:
将基准测试中使用的fib(40)改为fib(20)再次测试:
如何提升基准测试的精度
- benchtime
通过上面的两次测试,可以看到当n为40的时候,测试只有一次,而n为20的时候,测试有一万次,我们可以认为当基准测试运行了几千次迭代的时候,可以获得每个运行的平均值,但是只运行了几次的基准测试,我们认为获得的单个操作的平均值是不准确的,可以通过增加迭代次数来提高基准测试的精度,使用-benchtime
标识来增加运行时间,运行n为20与30的基准测试。
下图显示了将超时时间改为10s后的结果,迭代次数自然也大概增加了10倍,对比两种情况下(n为20或30)时候单个运行的平均值。
fib(20)的情况:
可以看到平均值的变化不是特别大
fib(30)的情况:
可以看到平均值的变化特别大
- count
对于每次操作时以十位数或个位数纳秒为单位计算的函数来说,指令重新排序对代码对齐的相对效应都将对结果产生影响。
修改count标识可以多次运行基准测试
以n=20为例:
基于此所计算的平均值将更加精确。
简单地对代码进行调优进行基准测试的对照实验
简单地,通过预设值特定值的返回,可以减少斐波那契数列函数的递归次数。
修改代码如下:
package fib
func fib(n int) int {
switch n {
case 0: return 0
case 1: return 1
case 2: return 1
case 3: return 2
case 4: return 3
default: return fib(n-1)+fib(n-2);
}
}
对比结果如下:
上面为为修改前,下面为修改后
可以看到减少了递归次数之后,基准测试确实显示性能更好了
内存分配的基准测试
利用bufio软件包,来汇报内存开销。
模板如下:
func BenchmarkReadOrLoad(b *testing.B) {
b.ReportAllocs() // !
for i := 0; i < b.N; i++ {
// 被测试功能
}
}
使用命令:go test -run=^$ -bench=. -benchmem bufio github.com/github-name/XXX