基准测试函数必须满足四要素才能运行:函数名以Benchmark开头、参数为*testing.B、文件名以_test.go结尾、与被测代码同包;缺一则go test -bench静默跳过,常见报错为no benchmarks to run或输出空白。

基准测试函数写不对,根本跑不起来
Go 的 go test -bench 不会报错,只会静默跳过——常见现象是执行后输出 no benchmarks to run 或完全空白。核心原因就四个硬性条件缺一不可:Benchmark 开头的函数名、*testing.B 参数类型、放在 xxx_test.go 文件里、且与被测代码同包。
容易踩的坑:
- 把
func BenchmarkXxx(t *testing.T)写成单元测试签名,参数类型错了,直接忽略 - 文件名写成
benchmark.go或perf.go,不是_test.go后缀,不会被扫描 - 函数定义在独立 package(比如
benchutil)里,而没 import 到主包测试文件中 - 微服务里常有跨 package 的 handler 或 service 层,测试时必须把
Benchmark函数和被测逻辑放在同一包,或用导出接口调用
HTTP handler 基准测试怎么模拟真实请求
别启动真实 server,用 net/http/httptest 就够了。它能构造 *http.Request 和 http.ResponseWriter 实现零端口压测,避免网络栈干扰和端口冲突。
关键点:
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
req := http.NewRequest("GET", "/", nil)必须复用,不能在循环里反复创建——否则测的是http.NewRequest而不是 handler 本身 -
recorder := httptest.NewRecorder()也得在循环外初始化,否则每次都会新建缓冲区,干扰内存统计 - 循环体内调用
handler(recorder, req)后,记得recorder.Flush()清空响应缓冲,模拟连续请求状态 - 如果 handler 依赖 context 或中间件(如 auth、logging),需手动构造带值的
context.Context并注入到req中,否则逻辑短路
GOMAXPROCS 和 -cpu 标志影响并发基准结果
输出里看到的 BenchmarkHandler-4 后缀不是随便加的——它表示当前运行环境的 GOMAXPROCS=4,即调度器最多使用 4 个 OS 线程。这对微服务 benchmark 极其关键:HTTP server 默认启用 goroutine 并发,GOMAXPROCS 直接决定并行吞吐上限。
实操建议:
- 跨机器比对前,必须统一设置
GOMAXPROCS,例如GOMAXPROCS=8 go test -bench=. -benchmem -
-cpu参数只对b.RunParallel生效,普通Benchmark函数设了也无效;想测并行 handler 性能,得显式写b.RunParallel(func(pb *testing.PB) { ... }) - CI 环境常默认
GOMAXPROCS=1,导致-4变成-1,ns/op 看似变好,实则掩盖并发瓶颈 - 微服务中若用了
sync.Pool或连接池,GOMAXPROCS改变会显著影响对象复用率和 GC 压力,必须纳入报告变量
生成可对比的基准报告必须用 benchstat
go test -bench=. 单次输出波动大,尤其在容器或 CI 环境下 CPU 抢占频繁。直接看 ns/op 数值容易误判优化效果——真正可靠的结论来自多次采样后的统计显著性。
正确链路:
- 先用
go test -bench=. -benchmem -count=5 -json > old.json导出结构化数据 - 再跑优化后版本,同样命令导出
new.json - 用
benchstat解析:benchstat old.json new.json,它自动计算均值、标准差、p-value 和 delta - 注意
benchstat对输入格式敏感:必须是原始go test -json输出,不能是人工截取或 CSV 转换 - 如果微服务涉及外部依赖(如 DB、Redis),基准测试应 mock 掉这些调用,否则
benchstat对比的是“网络延迟 + 逻辑”,而非纯 Go 代码性能
ns/op 偏差超过 20%。每次报告前,得确认环境变量、runtime 设置、mock 粒度都一致,否则数字再漂亮也没法归因。

















