当我们尝试去优化代码的性能时,首先得知道当前的性能怎么样,得到一个基准性能。Go语言标准库内置的 testing 测试框架提供了benchmark的能力。本文主要介绍 如何使用benchmark 进行基准测试,以及如何提高benchmark 的精准度,最后介绍了两个工具,帮助我们更加方便的进行benchmark。
This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on Medium. Thank you very much.
稳定的测试环境
性能测试受环境的影响很大,为了保证测试的可重复性,在进行性能测试时,尽可能地保持测试环境的稳定。
- 机器处于闲置状态,测试时不要执行其他任务,也不要和其他人共享硬件资源。
- 机器是否关闭了节能模式,一般笔记本会默认打开这个模式,测试时关闭。
- 避免使用虚拟机和云主机进行测试,一般情况下,为了尽可能地提高资源的利用率,虚拟机和云主机 CPU 和内存一般会超售,超售机器的性能表现会非常地不稳定。
- 一次测试是没有意义的,统计意义下可对比的结果是关键,对于一般的benchmark,我一般会重复执行20次。
benchmark 是如何工作的
benchmark 其实就是重复调用某个函数,然后记录函数的执行时间等指标,来度量它的性能。一个典型的benchamrk 函数如下所示:
|
|
benchmark 函数必须以 Benchmark 开始 我们可以这样运行它,都是等效的。
|
|
b.N
benchmark 用例的参数 b *testing.B
,有个属性 b.N
表示这个用例需要运行的次数。b.N
对于每个用例都是不一样的。
那这个值是如何决定的呢?b.N
从 1 开始,如果该用例能够在 1s 内完成,b.N
的值便会增加,再次执行。b.N
的值大概以 1, 2, 3, 5, 10, 20, 30, 50, 100 这样的序列递增,越到后面,增加得越快
进阶参数
count
控制运行次数,而不受由b.N 控制benchtime
控制运行时间,而受1s控制benchmem
度量内存分配的次数cpu
指定使用几个CPU核心,默认使用的是go
同时,benchmark 测试支持go test
的其他参数,比如cpuprofile
、memprofile
、trace
等
提升准确度
降低系统噪音:perflock
perflock
作用是限制 CPU 时钟频率,从而一定程度上消除系统对性能测试程序的影响,减少结果的噪声,进而性能测量的结果方差更小也更加可靠。
ResetTimer
如果在 benchmark 开始前,需要一些准备工作,如果准备工作比较耗时,则需要将这部分代码的耗时忽略掉。
StopTimer & StartTimer
StopTimer & StartTimer
也是相同原理,每次函数调用前后需要一些准备工作和清理工作,我们可以使用 StopTimer
暂停计时以及使用 StartTimer
开始计时。
度量 benchmark
benchstat 是官方提供的一个对比工具,用于比较两次benchmark之间的性能差别
Benchstat computes statistical summaries and A/B comparisons of Go benchmarks.
我们用benchstat对比一下 bubbleSort 跟quickSort 的性能
|
|
|
|
这样的结果是不是很清晰?我们可以把他放在报告或者github issue 中,很专业。
一些第三方的工具
bench
bench
是一个为 Go 程序提供集成性能测量、自动性能锁定、统计分析和颜色指示的基准测试工具。
funcbench
funcbench
是 Prometheus 项目中用于自动化 Go 代码基准测试和性能比较的工具。以下是其主要特点和功能:
支持比较本地分支与GitHub 分支、性能锁定、性能比较 等特点,有利于提高开发效率。如果项目比较大,可以参考这种方式。