BenchmarkAdd(b testing.B)跑不起来是因为函数名未以Benchmark开头、参数不是testing.B或文件未命名_test.go;go test -bench=.无输出数字是因单次执行过快,b.N可能为1即结束,需加-benchmem或-benchtime=5s。

为什么BenchmarkAdd(b *testing.B)跑不起来
函数名没以Benchmark开头、参数不是*testing.B、文件没放在_test.go里——三者缺一,go test -bench=.就当它不存在,还不报错。最常见的是写成benchmarkAdd(小写开头)或传了*testing.T。确认方式很简单:删掉函数体,只留签名,再跑go test -bench=.,如果输出里没出现这行函数名,说明根本没被识别。
为什么go test -bench=.没输出数字
不是代码错了,是单次执行太快,Go 默认只跑够 1 秒,b.N可能被设为 1 就结束了,直接跳过统计。典型现象是命令返回空行,也没错误提示。
- 加
-benchmem常能触发输出(内存分配哪怕微小也更容易被捕捉) - 用
-benchtime=5s强制延长最低运行时间 - 对极快操作(比如整数加法),在循环里手动重复逻辑:
for j := 0; j ,再把<code>b.N当外层循环
怎么避免初始化开销污染耗时结果
建 map、生成测试数据、打开文件这些操作,本不该算进“算法耗时”里。但默认从函数入口就开始计时,一不小心就把 setup 时间全算进去了。
-
b.StopTimer()必须在 setup 完毕后立刻调用,暂停计时 -
b.ResetTimer()必须紧跟其后,清零已记录时间并重启计时器——顺序不能反,否则 setup 阶段仍被计入 - 主循环必须放在
b.ResetTimer()之后,且每次迭代要重置可变状态(比如切片、map 写入),否则后续轮次可能走缓存捷径
例如测 map 查找,setup 部分建好 map 后,必须先b.StopTimer()再b.ResetTimer(),然后才开始for i := 0; i 查值。
立即学习“go语言免费学习笔记(深入)”;
为什么结果里 ns/op 看着不准
编译器可能把函数调用整个优化掉,尤其返回值没被使用时。你看到的“0 ns/op”或异常低的数字,大概率不是真快,是压根没执行。
- 把结果赋给局部变量并用
_ = result确保不被忽略 - 别在循环里做 I/O、打印、或依赖全局变量的副作用,否则
b.N失去意义 - 用
-benchmem一起看B/op和allocs/op,内存分配突增往往暴露逃逸或隐式分配(比如fmt.Sprintf)
真正难的不是让 Benchmark 跑起来,而是确保它测的确实是那个算法本身——变量作用域、初始化时机、甚至编译器优化开关,都可能让结果偏离真实场景一个数量级。


















