go基准测试需满足四要素:文件名以_test.go结尾且与被测代码同包;函数名以benchmark开头、首字母大写、签名必须为func benchmarkxxx(b *testing.b);初始化后调用b.resettimer;循环必须使用b.n。

Go 语言环境搭好后,go test -bench 就能直接跑基准测试——但前提是文件名、函数签名、初始化时机全对,错一个就静默失败,连输出都没有。
文件必须叫 xxx_test.go
Go 测试框架只扫描以 _test.go 结尾的文件。哪怕你把 BenchmarkFoo 写在 utils.go 或 main.go 里,go test -bench=. 也完全看不到它。
- 正确命名:比如
stringutil_test.go、json_test.go - 错误命名:
benchmark.go、perf.go、utils_test.go.bak—— 全部无效 - 文件需和被测代码在同一包下(不能跨包 import 后测)
函数签名必须是 func BenchmarkXxx(b *testing.B)
不是 *testing.T,不是 func(b int),也不是 BenchXxx 或 benchmark_xxx。大小写、参数类型、前缀缺一不可。
- 合法:
func BenchmarkMapSet(b *testing.B) - 非法:
func BenchmarkMapSet(t *testing.T)(用了 T)、func benchMapSet(b *testing.B)(没大写 B)、func Benchmarkmapset(b *testing.B)(驼峰不规范) - 导出要求:函数名首字母必须大写,否则测试框架根本不会反射到它
必须用 b.N 循环,且 ResetTimer 要放在初始化之后
b.N 是框架动态决定的迭代次数,不是固定值。手动写死 for i := 0; i 会导致结果不可比;漏掉 <code>b.ResetTimer() 则初始化开销(如 make([]byte, 1e6))全算进耗时里。
- 典型错误:在
data := make([]int, 10000)之后没调b.ResetTimer(),测出来的是“分配+计算”,不是纯计算 - 正确顺序:预分配 →
b.ResetTimer()→for i := 0; i - 如果循环内有可变逻辑(比如不同 size),别用
if b.N == 1做一次性 setup ——b.N每次运行都可能不同
运行命令与常用参数组合
基础命令能跑,但没加参数往往得不到可靠数据。默认只跑 1 秒,单次结果波动大,容易误判优化效果。
-
go test -bench=.:跑当前目录所有Benchmark*函数 -
go test -bench=^BenchmarkJSONParse$:精确匹配,避免正则误中其他函数 -
go test -bench=. -benchmem:加上内存分配统计(allocs/op和B/op) -
go test -bench=. -benchtime=5s -count=5:延长单次采样时间 + 重复 5 次取平均,显著降低噪声影响 - 注意:
-bench=.不会自动触发单元测试;加-run=^$可显式屏蔽所有 Test*,只跑 Benchmark
最容易被忽略的不是语法,而是环境干扰——笔记本节能模式、后台进程、CPU 频率浮动,都会让两次 go test -bench=. 结果差 15% 以上。真要对比优化效果,得关掉 Turbo Boost、清空 CPU 缓存(或用 perflock)、单次只跑一个 benchmark,而不是堆在一起跑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











