Golang基准测试Benchmark Test的基本写法

Go基准测试函数名必须以Benchmark开头,定义在_test.go文件中,仅接收*testing.B参数且无返回值,主体需用b.N循环并调用b.ResetTimer()。

Go基准测试函数名必须以Benchmark开头

Go的testing包只识别形如BenchmarkXXX的函数为基准测试,且必须接收*testing.B参数。名字不满足规则(比如写成TestBenchmarkbenchFoo)会导致go test -bench完全忽略该函数。

常见错误:把基准测试和普通单元测试混写在同一文件但没注意命名规范,结果-bench=.跑出来是no benchmarks to run

  • 函数必须定义在_test.go文件中
  • 首字母大写的XXX部分建议体现被测逻辑,例如BenchmarkMap

    Insert
    BenchmarkJSONMarshal
  • 不能有返回值,也不能额外参数(仅*testing.B

基准测试主体必须调用b.N循环

*testing.Bb.N不是固定次数,而是由Go测试框架根据预热和稳定性自动确定的迭代次数。你必须在b.ResetTimer()之后、实际测量代码里显式使用for i := 0; i 包裹待测逻辑,否则测的是0次或1次,结果无意义。

容易踩的坑:直接在循环外执行一次操作,或者用b.ReportAllocs()但忘了加循环——这时b.N可能是1,所有耗时/内存数据都失真。

  • 不要手动设b.N = 10000,它会被框架覆盖
  • 耗时敏感的操作(如初始化开销大的对象)应放在b.ResetTimer()之前
  • 如果要排除某段预处理时间,用b.StopTimer()b.StartTimer()控制计时区间

运行基准测试必须加-bench参数

go test默认不运行任何Benchmark函数,必须显式传参。最常用的是go test -bench=.(点号表示匹配所有),也可以用正则精确指定,比如go test -bench=BenchmarkJSON

注意:-bench会自动启用-cpuprofile等底层支持,但不会运行Test函数——除非同时加-run。这点常被忽略,导致误以为“基准测试失败”其实是没跑起来。

  • -benchmem可同时显示内存分配统计(推荐必加)
  • -benchtime=5s可延长总运行时间,让结果更稳定(默认1秒)
  • -count=3可重复运行三次取平均值,避免单次抖动干扰
func BenchmarkAdd(b *testing.B) {
    var x, y = 1, 2
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        _ = x + y
    }
}

这个例子看起来简单,但漏掉b.ResetTimer()或没用b.N循环,就不是有效的基准测试。真实场景中,初始化DB连接、构建大结构体、预热缓存这些动作,都需要仔细安排在计时开关之间。