当前位置:首页 > 文章列表 > Golang > Go教程 > Go benchmark 怎样避免编译器优化掉被测代码

Go benchmark 怎样避免编译器优化掉被测代码

来源:17golang原创 2026-10-14 04:28:11 0浏览 收藏

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(),不要包一层自定义函数或改成等价表达式。

Go testing.B 与 b.Loop、被测函数返回值和编译器保活边界的静态结构说明图
图1: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 不应在并行基准之间共享可变状态,也不要在循环里打印。

Go 旧式 b.N 基准中输入、目标计算、包级结果汇总与计时边界的静态结构说明图
图2:结果汇总结构说明图,展示旧式 b.N 基准如何保留被测计算。
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 在循环前做了昂贵初始化时使用它;如果初始化本身就是要测的对象,则不要为了好看而排除它。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go fuzz 测试怎样限制输入并保留回归样例Go fuzz 测试怎样限制输入并保留回归样例
上一篇
Go fuzz 测试怎样限制输入并保留回归样例
Go pprof 怎样从内存剖析定位保留对象
下一篇
Go pprof 怎样从内存剖析定位保留对象
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    465次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    527次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    545次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    495次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    314次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码