Go benchmark中禁用log.Fatal或panic,应使用b.Error()或b.Fatal()报告错误;setup阶段错误用b.Fatal()提前退出,循环内错误用b.Error()记录后continue,避免中断整个测试流程。
log.Fatal 或 panic 捕获错误Go 的 testing.B 函数运行
在受控环境中,一旦触发 panic 或调用 log.Fatal,整个基准测试会立即终止,且不报告任何结果(甚至不显示 BenchmarkXXX 已执行)。这不是“捕获错误”,而是让测试崩溃。
b.Error() 或 b.Fatal() 报告(仅限失败时)b.Fatal() 会标记该次 benchmark 失败并停止当前函数,但不会中断整个 go test -bench 流程BenchmarkXxx 开头处理,避免进入 b.ResetTimer() 后才出错testing.B 中安全调用可能出错的函数典型场景是被测函数返回 (result, error),比如 json.Marshal、http.Post 模拟或数据库查询。直接忽略错误会导致结果不可信;用 if err != nil { panic(err) } 会让 benchmark 崩溃。
b.ResetTimer() 之前 —— 如果 setup 阶段就失败,说明测试环境有问题,应提前退出b.StopTimer() + b.StartTimer() 隔离错误处理开销b.Fatal(),它会中断整个 benchmark 迭代;改用 b.Error() 记录后 continue
func BenchmarkJSONMarshal(b *testing.B) {
data := map[string]int{"x": 1, "y": 2}
// setup 阶段检查
if _, err := json.Marshal(data); err != nil {
b.Fatal("setup failed:", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
out, err := json.Marshal(data)
if err != nil {
b.Error("marshal failed at iteration", i, ":", err)
continue // 跳过本次,不计入计时
}
_ = out
}
}
go test -bench 不显示错误详情?检查是否漏了 b.Error() 调用默认情况下,benchmark 只输出耗时和内存分配数据,b.Error() 的内容不会自动打印,除非加上 -benchmem -v 参数。很多开发者以为“没报错”其实是错误被静默吞掉了。
-v: go test -bench=. -benchmem -v
b.Error() 和 b.Fatal() 的输出只在失败时显示;如果 benchmark 成功完成(哪怕中间有 b.Error()),也不会中断,但错误信息仍会出现在终端b.Error() 是记录错误但继续跑完所有 b.N 次;b.Fatal() 是立刻终止当前 benchmark 函数真实代码里错误分支往往比正常路径慢得多(比如网络超时、磁盘 I/O 失败重试),直接把错误处理混进主循环会严重污染 ns/op 数据。你测的不是“成功路径性能”,而是“平均错误混合路径性能”。
json.Unmarshal)b.N 是动态调整的,一旦某次迭代因错误导致耗时剧增,整个 b.N 可能被大幅下调,最终你看到的 ns/op 其实来自极少量样本,且无法复现**。务必先用小规模 -benchtime=10ms 验证逻辑稳定再拉长测试时间。