Go中性能测试(Benchmark)基准测试

169 阅读1分钟

前言

基准测试是一种测试代码性能的方法。想要测试解决同一问题的不同方案的性能,以及查看 哪种解决方案的性能更好时,基准测试就会很有用。基准测试也可以用来识别某段代码的 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语言实战》