Go benchmark 怎样避免编译器优化掉被测代码
Go benchmark 最容易被忽略的一类问题,是循环看起来执行了很多次,实际测到的却不是目标函数。典型代码把返回值赋给局部变量后立即丢弃,编译器发现这段计算没有可观察副作用,就可能把它简化甚至删除。解决办法是:Go 1.24 及以后优先使用精确写法 for b.Loop();旧版本继续使用 b.N 时,则把返回值汇总到包级变量。
b.Loop()的条件必须原样写在 for 中,循环体内的调用结果会被 testing 保活。- 旧式
b.N不能只把结果放进循环内的临时变量,使用包级 sink 才能让计算保持可观察。 - 输入准备放在计时前;旧式写法用
ResetTimer,多次运行再用 benchstat 比较。
先判断:基准循环是不是只剩空调用
假设要测一个返回整数的哈希或解析函数,下面的写法表达了“我关心函数耗时”,但没有表达“返回值必须留下来”。如果函数没有 I/O、全局写入或其他可见副作用,优化器就有机会认为调用结果不影响程序。
package demo
import "testing"
func BenchmarkHash(b *testing.B) {
for i := 0; i
这里的关键不是“每次都要打印结果”。打印会改变被测对象;正确做法是保存结果,但不要把日志、分配或锁竞争混进计时区域。
用 b.Loop 保住循环体的工作量
当前 testing 文档推荐新基准使用 B.Loop。它不只是把 b.N 换成另一种循环:在 for b.Loop() { ... } 的大括号内,函数调用的参数、返回值和赋值变量会被保活,避免被测调用被完全优化掉。条件必须精确写成 b.Loop(),不要包一层自定义函数或改成等价表达式。

func BenchmarkHashLoop(b *testing.B) {
input := "go benchmark"
for b.Loop() {
// b.Loop 会让循环体内的调用和返回值保持可观察。
fastHash(input)
}
}
func BenchmarkHashLoopUsed(b *testing.B) {
input := "go benchmark"
for b.Loop() {
// 显式接住结果,便于表达测试意图和后续扩展统计。
got := fastHash(input)
_ = got
}
}
第二个示例里的 _ = got 主要是说明意图;在支持 b.Loop 的 Go 版本中,真正重要的是循环条件和循环体位置。不要把 b.Loop 与 for i := 0; i 同时套在一个 benchmark 里。
旧式 b.N 写法为什么需要结果汇总
如果项目还要兼容没有 B.Loop 的 Go 版本,可以保留 b.N,但让结果流向包级变量。这样结果具有跨函数调用仍可观察的存储位置,编译器不能把整段计算简单视作“完全没用”。这个 sink 不应在并行基准之间共享可变状态,也不要在循环里打印。

package demo
import "testing"
var benchmarkSink uint64
func BenchmarkHashN(b *testing.B) {
input := "go benchmark"
b.ResetTimer()
for i := 0; i
把计时边界和结果可信度一起复查
基准修好后,先只比较同一台机器、同一输入和同一编译配置下的结果。b.Loop 会自动处理迭代与计时;b.N 版本则要确认循环确实执行了 b.N 次,且 setup 没有被意外算进耗时。
| 检查点 | 正确做法 | 常见误区 |
|---|---|---|
| 循环条件 | 新代码写成 for b.Loop() | 与 b.N 双重循环,或封装后再调用 |
| 结果去向 | Loop 内保活;旧式写法用包级 sink | 只赋给循环内临时变量后丢弃 |
| 输入准备 | 计时前构造,旧式写法随后 ResetTimer | 把 make、读文件和解析初始化混在循环中 |
| 重复运行 | go test -run '^$' -bench BenchmarkHash -count=5 后用 benchstat | 只看一次 ns/op 就下结论 |
# 只运行目标 benchmark,重复采样以减少偶然抖动。 go test -run '^$' -bench '^BenchmarkHash' -count=5 # 对两组已保存的基准结果做统计比较。 benchstat before.txt after.txt
命令中的正则只负责筛选测试名;它不能证明实现一定没有被优化。最终仍要回到代码检查:目标调用是否位于计时循环内、返回值是否有存活路径、setup 是否被排除、输入规模是否一致。
相关问题
b.Loop 能不能和 b.N 一起使用?
不能。一个 benchmark 选择其中一种循环方式即可;新代码优先使用 b.Loop,旧代码才继续按 b.N 编写。
为什么不建议在 benchmark 里 fmt.Println 结果?
输出会带来格式化、系统调用和锁等额外成本,改变被测路径。用包级 sink 或 b.Loop 的保活语义即可保留结果。
ResetTimer 什么时候需要?
旧式 b.N benchmark 在循环前做了昂贵初始化时使用它;如果初始化本身就是要测的对象,则不要为了好看而排除它。
Go fuzz 测试怎样限制输入并保留回归样例
- 上一篇
- Go fuzz 测试怎样限制输入并保留回归样例
- 下一篇
- Go pprof 怎样从内存剖析定位保留对象
-
- Golang · Go教程 | 21分钟前 | go ·
- Go math/big 怎样安全解析高精度整数
- 378浏览 收藏
-
- Golang · Go教程 | 29分钟前 |
- Go strings.Cut 怎样拆分键值配置
- 494浏览 收藏
-
- Golang · Go教程 | 31分钟前 |
- Go strconv.QuoteRune 怎样让控制字符安全显示在日志中
- 121浏览 收藏
-
- Golang · Go教程 | 33分钟前 |
- Go net/mail 怎样解析带显示名的地址
- 415浏览 收藏
-
- Golang · Go教程 | 36分钟前 |
- Go database/sql 怎样设置连接池上限
- 223浏览 收藏
-
- Golang · Go教程 | 38分钟前 |
- Go database/sql 连接池上限与等待监控的配置方法
- 428浏览 收藏
-
- Golang · Go教程 | 58分钟前 |
- Go websocket 升级前怎样校验来源
- 401浏览 收藏
-
- Golang · Go教程 | 1小时前 | 标准库 · HTTP · go · Go ReverseProxy net/http/httputil DumpRequestOut 反向代理日志
- Go net/http/httputil 怎样记录请求转发细节
- 455浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go build tags 怎样区分平台实现
- 175浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 465次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 527次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 545次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 495次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 314次使用
-
- Golang 单元测试和基准测试实例详解
- 2022-12-23 275浏览
-
- Go语言工程实践单元测试基准测试示例详解
- 2023-02-25 257浏览
-
- Go error wrapping 实战:别让错误日志只剩一句 failed
- 2026-06-01 151浏览
-
- Go pprof 排查慢接口:别只会看火焰图,先把问题问对
- 2026-06-01 101浏览
-
- Go Flight Recorder 实战:线上偶发卡顿,别再只靠日志碰运气
- 2026-06-01 323浏览

