前言
基准测试是一种测试代码性能的方法。想要测试解决同一问题的不同方案的性能,以及查看 哪种解决方案的性能更好时,基准测试就会很有用。基准测试也可以用来识别某段代码的 CPU 或者内存效率问题,而这段代码的效率可能会严重影响整个应用程序的性能。许多开发人员会用 基准测试来测试不同的并发模式,或者用基准测试来辅助配置工作池的数量,以保证能最大化系 统的吞吐量
Benchmark
和单元测试文件一样,基准测试的文件名也必须以_test.go 结尾。同时也必须导入 testing 包。
package testinglearn
import (
"fmt"
"testing"
)
func BenchmarkSprintf(b *testing.B) {
number := 10
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Sprintf("%d", number)
}
}
第一个基准测试函数,名为 BenchmarkSprintf。 基准测试函数必须以 Benchmark 开头,接受一个指向 testing.B 类型的指针作为唯一参数。 为了让基准测试框架能准确测试性能,它必须在一段时间内反复运行这段代码,所以这里使用了 for 循环,
for i := 0; i < b.N; i++ {
fmt.Sprintf("%d", number)
}
注意for循环中的条件i < b.N ,这是一个需要注意的地方。
基准测试框架默认会在持续 1 秒的时间内,反复调用需要测试的函数。测试框架每次调用测 试函数时,都会增加 b.N 的值。第一次调用时,b.N 的值为 1。需要注意,一定要将所有要进 行基准测试的代码都放到循环里,并且循环要使用 b.N 的值。
否则,测试的结果是不可靠的!
执行命令:
go test -v -run="none" -bench="BenchmarkSprintf"
执行结果:
goos: windows
goarch: amd64
pkg: gogo/test/testinglearn
cpu: Intel(R) Core(TM) i5-8200Y CPU @ 1.30GHz
BenchmarkSprintf
BenchmarkSprintf-4 14858995 76.48 ns/op
PASS
代码被执行了14858995次,平均每次 花费了 258 纳秒
如果想让程序执行测试的时间更长一些,可以使用-benchtime
benchtime
通过benchtime给定执行测试时间
go test -v -run="none" -bench="BenchmarkSprintf" -benchtime="3s"
goos: windows
goarch: amd64
pkg: gogo/test/testinglearn
cpu: Intel(R) Core(TM) i5-8200Y CPU @ 1.30GHz
BenchmarkSprintf
BenchmarkSprintf-4 39326726 83.53 ns/op
PASS
ok gogo/test/testinglearn 3.920s
benchmem
运行基准测试时,另一个很有用的选项是-benchmem 选项。这个选项可以提供每次操作分 配内存的次数,以及总共分配内存的字节数。
执行命令:
go test -v -run="none" -bench="BenchmarkSprintf" -benchtime="2s" -benchmem
执行结果:
...省略其他信息
BenchmarkSprintf-4 29419479 76.94 ns/op 2 B/op 1 allocs/op
这次输出的结果会多出两组新的数值:
一组数值的单位是 B/op,
另一组的单位是 allocs/op
单位为 allocs/op 的值表示每次操作从堆上分配内存的次数,你可以看到 Sprintf 函数每次操作都会从堆上分配1个值(1 allocs/op)
单位为 B/op 的值表示每次操作分配的字节数,可以看到Sprintf 函数1次分配总共消耗了2字节的内存 (2 B/op)
参考书籍《Go语言实战》