如何在Golang中实现自定义Benchmark_Golang testing.B自定义性能测量示例
技术百科
P粉602998670
发布时间:2026-01-01
浏览: 次 自定义 Benchmark 函数必须命名为 BenchmarkXxx,接收 *testing.B 参数,通过 go test -bench=. 运行;需在 b.N 循环外初始化并调用 b.ResetTimer(),避免测量初始化开销。
如何在 Go test 文件中定义并运行自定义 Benchmark 函数
Go 的 testing.B 是唯一合法的 benchmark 入口,所有自定义性能测量必须以 BenchmarkXxx 形式定义,且函数签名固定为 func(*testing.B)。它不是普通函数调用,不能手动传参或直接执行——必须通过 go test -bench=.
触发。
常见错误是把 benchmark 写成普通函数、漏掉 b.ResetTimer()、或在 b.N 循环外做初始化却未排除耗时,导致结果失真。
- 函数名必须以
Benchmark开头,首字母大写 - 必须接收单个
*testing.B参数 - 循环体必须用
for i := 0; i ,不可硬编码次数 - 预热或初始化逻辑应放在
for循环之前,并调用b.ResetTimer()重置计时起点
为什么必须调用 b.ResetTimer() 和 b.StopTimer()
Go 默认从函数入口开始计时,但初始化(如构造 map、读配置、建连接)不属于被测逻辑。若不干预,这些开销会污染 b.N 循环的平均耗时。
b.ResetTimer() 重置计时器,把后续 b.N 循环作为唯一测量区间;b.StopTimer() 暂停计时,适合在循环中穿插非关键操作(如日志打印、临时缓存清理),避免干扰核心路径。
- 初始化后、循环前调用
b.ResetTimer()是最常见且必要的操作 - 若循环体内需执行不可省略但非目标逻辑(如 sync.Pool Get/Pool),可用
b.StopTimer()+b.StartTimer()包裹 - 忘记
ResetTimer()会导致 benchmark 报出极低 QPS、极高 ns/op,数值完全不可比
如何测量不同输入规模下的性能变化(如 slice 长度递增)
标准 testing.B 不支持参数化 benchmark,但可通过闭包或子测试方式模拟多组输入。推荐在单个 Benchmark 函数内遍历不同规模,对每组调用 b.Run() 创建子 benchmark,便于横向对比。
注意:每个 b.Run() 子项独立计时,且会继承父项的 -benchmem 等标志,适合观察增长趋势。
func BenchmarkCopySlice(b *testing.B) {
sizes := []int{100, 1000, 10000}
for _, n := range sizes {
b.Run(fmt.Sprintf("Len%d", n), func(b *testing.B) {
data := make([]byte, n)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = append([]byte(nil), data...)
}
})
}
}
如何安全地在 benchmark 中使用并发(b.RunParallel)
b.RunParallel 用于模拟多 goroutine 并发调用同一逻辑,适用于测试锁竞争、channel 吞吐、sync.Pool 等场景。但它不保证总执行次数为 b.N,而是将 b.N 拆分给多个 goroutine 并行执行——实际调用次数 ≥ b.N,且无法控制 goroutine 数量(由 runtime 自动调度)。
关键约束:被测函数不能依赖共享可变状态,否则结果不可复现;所有初始化必须在 b.RunParallel 外完成。
- 传入的
func(*testing.PB)中,pb.Next()控制是否继续,必须用for pb.Next() { ... }循环包裹被测逻辑 - 不要在
pb.Next()循环内做初始化(如 new struct、open file),这会放大资源开销 - 并发 benchmark 的内存分配统计(
-benchmem)反映的是单次调用均值,不是总和
func BenchmarkConcurrentMapSet(b *testing.B) {
m := make(map[int]int)
var mu sync.RWMutex
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mu.Lock()
m[1] = 1
mu.Unlock()
}
})
}
Go benchmark 的真实难点不在写法,而在于区分“测什么”和“怎么排除干扰”。比如 time.Now() 调用本身有开销,fmt.Sprintf 在循环里会掩盖核心逻辑性能,甚至 GC 周期都可能让结果抖动——这些都需要靠多次运行、关闭 GC(debug.SetGCPercent(-1))、或结合 pprof 进一步定位。
# 的是
# 放在
# 能让
# 多个
# 极高
# 适用于
# 自定义
# 计时器
# app
# 不支持
# go
# golang
# 循环
# 并发
# 编码
# 为什么
# 继承
# Struct
# map
# channel
# 闭包
# 遍历
# for
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- PHP主流架构怎么处理表单验证_规则与自定义【技巧
- Win11怎么设置ipv4地址_Windows 1
- 使用类变量定义字符串常量时如何实现类型安全的 Li
- Win11怎么看电池循环次数_Win11笔记本电池
- 如何在 Go 中正确反序列化 XML 多节点数组(
- c++的mutex和lock_guard如何使用
- 如何使用Golang处理静态文件缓存_提高页面加载
- Win11如何设置系统声音_Win11系统声音调整
- 如何在 Go 中可靠地测试含 time.Time
- 短链接怎么用php递归还原_多层加密链接的处理法【
- 如何使用Golang读取日志文件_Golang b
- php和redis连接超时怎么办_phpredis
- Win11怎么开启智能存储_Windows11存储
- Python异步网络编程_aiohttp说明【指导
- php转mp4怎么设置帧率_调整php生成mp4视
- php本地部署支持nodejs吗_php与node
- 如何使用Golang捕获测试日志_Golang t
- 如何正确访问 Laravel 模型或对象的属性而非
- 如何在Windows上设置闹钟和计时器_系统自带的
- 如何在Windows中创建新的用户账户?(标准与管
- 如何使用正则表达式批量替换重复的星号-短横模式为固
- php中::能用于接口静态方法吗_接口静态方法调用
- Win11声音太小怎么办_Windows 11开启
- Win11如何设置计划任务 Win11定时执行程序
- Windows10电脑怎么设置文件权限_Win10
- Win11怎么设置快速访问主页_Windows11
- 如何使用Golang捕获并记录协程panic_保证
- Go 语言标准库为何不提供泛型切片的 Contai
- 如何在 Go 中正确初始化结构体中的 map 字段
- Win11关机快捷键是什么_Win11快速关机方法
- Python路径拼接规范_跨平台处理说明【指导】
- Win11怎么更改账户头像_Windows 11自
- 如何在Golang中配置代码格式化工具_使用gof
- Win11怎么更改鼠标指针方案_Windows11
- Python对象生命周期管理_创建销毁解析【教程】
- Python性能剖析高级教程_cProfileLi
- 如何在 ACF 中正确更新嵌套多层 Group 字
- Win11怎么查看局域网电脑_Windows 11
- 如何使用Golang搭建Web开发环境_快速启动H
- 如何使用Golang管理跨项目依赖_Golang多
- VSC怎么配置PHP的Xdebug_远程调试设置步
- php修改数据怎么批量改状态_批量更新status
- 如何在Golang中使用replace替换模块_指
- Windows系统时间服务错误_W32Time服务
- Win10系统怎么查看网络连接状态_Windows
- php下载安装包太大怎么下载_分卷压缩下载方法【教
- ACF 教程:如何正确更新嵌套在多层 Group
- php文件怎么变mp4保存_php输出视频流保存为
- c++的位运算怎么用 与、或、异或、移位操作详解【
- Win11怎么设置ip地址_Windows 11手

QQ客服