go test 原生支持基准测试,需满足:文件名以_test.go结尾、函数名以Benchmark开头、参数为*testing.B;运行需加-bench=.参数,且循环必须用b.N控制。

确认 go test 支持基准测试(benchmark)功能
Go 原生 go test 已内置基准测试能力,无需额外安装工具,但必须满足两个前提:GOOS 和 GOARCH 环境变量已正确设置(通常默认即满足),且测试文件名以 _test.go 结尾、函数名以 Benchmark 开头、接收 *testing.B 参数。
- 错误写法:
func BenchmarkAdd() {}—— 缺少*testing.B参数,运行时会被忽略 - 正确写法:
func BenchmarkAdd(b *testing.B) {} - 运行命令必须显式启用基准测试:
go test -bench=.,不加-bench参数时默认只跑单元测试 - 首次运行会自动编译生成临时二进制,后续执行受
GOCACHE影响;如需排除缓存干扰,可加-count=1 -gcflags="all=-l"
编写一个可复现的 Benchmark 函数
基准测试不是“跑一次看耗时”,而是让 b.N 自动调整迭代次数,使总执行时间稳定在约 1 秒左右,再据此反推单次操作开销。因此函数体里必须用 b.N 控制循环,不能硬编码次数。
func BenchmarkStringConcat(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = "hello" + "world"
}
}
-
b.ResetTimer()可在初始化代码后调用,排除 setup 阶段对计时的影响 -
b.ReportAllocs()开启内存分配统计,输出中会多出B/op和allocs/op - 避免在循环内做非被测逻辑(如打印、文件 I/O),否则测的是 IO 而非目标代码
- 若被测函数有副作用(如修改全局变量),需在每次循环内重置状态,否则结果不可靠
使用 -benchmem 和 -benchtime 控制输出精度
-benchmem 是关键开关,不加它就不会显示内存分配数据;-benchtime 决定基准测试至少运行多久(默认 1s),调大可提升结果稳定性,尤其对极快操作(纳秒级)。
-
go test -bench=. -benchmem—— 输出包含内存分配统计 -
go test -bench=. -benchmem -benchtime=5s—— 每个 benchmark 至少跑 5 秒,减少随机波动 -
go test -bench=BenchmarkMapGet -benchmem -count=3—— 重复运行 3 次取平均值,适合观察方差 - 注意:
-benchtime不是“最多运行时间”,而是“最少运行时间”,b.N会自动放大以满足该时长
区分 Benchmark 和 Example 的用途边界
新手常误把 Example 函数当性能测试用——它只用于文档生成和简单验证,不参与任何计时或迭代,go test 默认也不执行它(除非加 -run=Example)。
立即学习“go语言免费学习笔记(深入)”;
-
ExampleXXX():仅检查是否能编译+运行成功,输出是否匹配注释末尾的// Output: -
BenchmarkXXX(b *testing.B):强制要求b.N循环,由测试框架控制节奏与计时 - 两者命名空间隔离,同名函数不会冲突,但混用会导致预期外的行为(比如想压测却只跑了单次 Example)
- 如果需要对比不同实现(如 map vs sync.Map),应分别写独立的
Benchmark函数,而非在同一个函数里 if-else 切换
b.N 的自适应机制容易掩盖短路径下的 CPU 频率变化或编译器优化;若发现结果波动大,优先检查是否禁用了编译器优化(-gcflags="-l -N")、是否在虚拟机中运行、以及是否开启了 CPU 节能策略。











