结论:基准测试写在 _test.go 里以 BenchmarkXxx(b *testing.B) 命名,go test -bench=. -benchmem 运行;框架自动调整 b.N 使测试时长足够,循环体 for i := 0; i < b.N; i++。靠谱的关键是:重置计时排除准备成本、防止编译器优化掉被测代码、报告分配情况。

展开:范式与错误对照:

func BenchmarkConcat(b *testing.B) {
    b.ReportAllocs()          // 报告 B/op 和 allocs/op
    parts := genParts(1000)   // 准备数据:计时外
    b.ResetTimer()            // 重置计时,排除准备开销
    var sink string
    for i := 0; i < b.N; i++ {
        sink = concat(parts)  // 结果赋给包级 sink 防优化
    }
    _ = sink
}

常见错误清单:1)忘记 ResetTimer——初始化时间被计入;2)结果未使用——编译器内联后发现无副作用,整个调用被消除,测出"纳秒级"假象(sink 模式或包级变量解决);3)在循环内做数据准备/随机数生成,测的是准备而非目标;4)忽略 allocs/op——很多优化(sync.Pool、预分配)的收益体现在分配次数而非纯时间;5)单次运行下结论——用 -count=10 + benchstat 做统计对比,避免环境噪声;6)b.RunParallel 测并发扩展性时忘了每个 P 有自己的 pb.Next 循环。易错点:timer 分辨率与短函数——被测函数快到几十纳秒时,循环开销占比升高,结果解释要谨慎。

追问方向:benchstat 的显著性检验、pprof 对 benchmark 产物做 CPU/内存剖析(-cpuprofile/-memprofile)。