Golang testing基准测试怎么做_Golang性能测试入门

1次阅读

基准测试函数必须满足三个条件:文件名以_test.go结尾、函数名以Benchmark开头且首字母大写、参数类型为*testing.B;否则go test -bench会静默忽略。

Golang testing基准测试怎么做_Golang性能测试入门

基准测试函数必须长什么样?

Go 的 Benchmark 函数不是随便起个名、写个循环就行——它必须严格满足三个条件,否则 go test -bench 会直接忽略,还不报错,静默跳过。

  • 文件名必须是 *_test.go(比如 utils_test.go
  • 函数名必须以 Benchmark 开头,且首字母大写(Benchmarkmapaccess ✅,benchmarkMapAccess ❌)
  • 参数类型必须是 *testing.B(不是 *testing.T,也不是无参)

漏掉任意一条,运行 go test -bench=. 就像没写一样。最常见的是把函数写在普通 .go 文件里,或者手误写成 func BenchmarkXxx(t *testing.T) —— 这种错误不会报错,只会让你对着空白输出发呆。

怎么写才测得准?别让初始化拖慢结果

基准测试真正要测的是“目标操作”,不是“建数据+跑操作”。但很多人把 make(map[int]int)strings.Builder{} 放在 b.N 循环里,结果测出来的是分配开销,不是算法本身。

  • 所有准备动作(造 map、填 slice、初始化 Struct)必须放在 b.ResetTimer() 之前
  • 如果准备阶段耗时明显,用 b.StopTimer()b.StartTimer() 手动包住非目标代码
  • 想看内存分配?必须显式调用 b.ReportAllocs(),光加 -benchmem 参数不够

正确示例:

立即学习go语言免费学习笔记(深入)”;

func BenchmarkMapRange(b *testing.B) {     m := make(map[int]int, 1000)     for i := 0; i < 1000; i++ {         m[i] = i * 2     }     b.ResetTimer()  // 计时从此开始     b.ReportAllocs()     for i := 0; i < b.N; i++ {         sum := 0         for _, v := range m {             sum += v         }         _ = sum     } }

运行命令和关键参数怎么选?

go test -bench=. 是起点,但默认行为容易误导:只跑约 1 秒、不显示内存、单次运行、受 CPU 负载干扰大。

  • -benchmem 看分配:否则你永远不知道那个快的函数是不是靠多分配换来的
  • -benchtime=3s5s,避免因太快导致采样不准
  • -count=3 多跑几次取平均,减少抖动影响
  • 精确匹配用正则锚点:-bench=^BenchmarkStringJoin$,避免匹配到 BenchmarkStringJoinWithPrefix

推荐日常调试组合:go test -bench=^BenchmarkMapRange$ -benchmem -benchtime=3s -count=3

对比两个实现,为什么不能只跑一次?

单次 go test -bench 输出只是原始数字,看不出“快了 37%”还是“慢了 2 倍”。真实优化必须靠统计对比。

  • 安装官方工具go install golang.org/x/perf/cmd/benchstat@latest
  • 分别保存两组结果:go test -bench=Concat -count=5 > old.txtgo test -bench=Builder -count=5 > new.txt
  • benchstat old.txt new.txt 输出带误差范围的 delta(比如 -85.20%

没用 benchstat 的对比,等于拿秒表掐两次时间然后心算——系统调度、GC、CPU 频率波动都会吃掉你的结论可信度。尤其当差异小于 10% 时,不跑多次 + 统计,基本就是猜。

text=ZqhQzanResources