Go testing.B RunParallel 如何估计并发吞吐
我第一次用 testing.B.RunParallel 时,最容易误读的是“开了多少个 goroutine”与“每秒完成多少次操作”之间的关系。RunParallel 默认按 GOMAXPROCS 创建 worker,把同一个 b.N 拆给它们;真正要估计并发吞吐,应在并行工作结束后用总迭代次数除以实际计时窗口,而不是拿 worker 数当吞吐。
pb.Next()在所有 worker 之间合计执行b.N次,b.N是总操作数。- 并发吞吐可按
float64(b.N) / b.Elapsed().Seconds()估算,再用ops/s报告。 - CPU 密集型任务先比较
-cpu,非 CPU 密集型任务才考虑SetParallelism(p);并发度提高不保证吞吐线性增长。
先把 RunParallel 的三个数量分开
RunParallel 的 worker 数默认是当前 GOMAXPROCS,调用 SetParallelism(2) 后才变为 2*GOMAXPROCS。这只是参与调度的 goroutine 数。每个 worker 都调用同一个 body,但 pb.Next() 负责从共享迭代计数中领取工作,所以所有 worker 加起来才覆盖 b.N 次操作。

| 量 | 含义 | 估计吞吐时的作用 |
|---|---|---|
GOMAXPROCS | 默认并行度基数 | 影响 worker 数,不等于每秒操作数 |
SetParallelism(p) | 把 worker 数调为 p*GOMAXPROCS | 用于等待型或外部依赖型负载的对比 |
b.N | 所有 worker 合计完成的迭代数 | 作为吞吐计算的总操作数 |
在 RunParallel 返回点计算 ops/s
Go 文档明确说明,RunParallel 报告的 ns/op 是整个并行基准的墙上时间,不是各 goroutine CPU 时间相加。要得到更直观的吞吐,可以在 RunParallel 返回后读取 b.Elapsed()。此时所有 worker 已结束,计算结果不会读到中间状态。
func BenchmarkParallelWork(b *testing.B) {
// 这里的工作体量应保持稳定,避免把随机等待当成吞吐变化。
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// 每次 Next 代表一次被计入 b.N 的基准操作。
doWork()
}
})
seconds := b.Elapsed().Seconds()
if seconds > 0 {
// b.N 是所有 worker 的总操作数,除以墙上时间得到 ops/s。
b.ReportMetric(float64(b.N)/seconds, "ops/s")
}
}
这个指标表达的是“该次基准计时窗口内完成的总操作数/秒”。不要把它解释成单个 goroutine 的速度,也不要把一次短跑的结果当作固定容量。go test -bench BenchmarkParallelWork -cpu=1,2,4 可以观察不同处理器并行度下的变化。
并发度提高后,为什么吞吐可能不再上升
如果 doWork 主要消耗 CPU,继续增加 worker 往往只会带来调度和竞争开销;这类场景通常先用 -cpu 比较。若操作包含网络、磁盘或锁等待,才有理由尝试 SetParallelism,但要同时记录外部服务限流、连接池大小和锁冲突,否则测到的可能只是排队时间。

func BenchmarkParallelIO(b *testing.B) {
// 非 CPU 密集型示例才考虑增加 worker,p 不是吞吐倍率。
b.SetParallelism(2)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// 外部依赖的延迟、连接池和限流都应在结论中单独记录。
doOneRequest()
}
})
if elapsed := b.Elapsed().Seconds(); elapsed > 0 {
// 在所有并行调用结束后一次性写入汇总指标。
b.ReportMetric(float64(b.N)/elapsed, "ops/s")
}
}
如果还要统计“成功操作数”或字节数,计数器必须使用 atomic.Int64 等并发安全类型,并在返回后读取。不要在 worker 内调用 StartTimer、StopTimer 或 ResetTimer,这些方法对整个 benchmark 有全局影响。
一张检查表:这个吞吐数字能不能比较
- 每次
pb.Next()对应的工作是否一致,是否把初始化误放进计时区间? b.N是否作为总迭代数使用,而不是乘以 worker 数?- 是否记录了
-cpu、GOMAXPROCS、SetParallelism和外部资源上限? - 是否运行多次并比较趋势,而不是依据单次 ops/s 下结论?
我更愿意把吞吐值当成同一环境下的比较坐标:先固定数据、依赖和基准命令,再改变一个并发参数。如果锁、连接池或服务端限流已经成为瓶颈,继续加并发只是在放大排队,不是在测量真实处理能力。
相关问题
RunParallel 的 b.N 是每个 goroutine 各自的次数吗?
不是。b.N 是整个 benchmark 的总迭代数,pb.Next() 在 worker 之间分配它;计算总吞吐时只使用一次 b.N。
SetParallelism(2) 能否说明吞吐提高两倍?
不能。它只把 worker 数调整为 2*GOMAXPROCS,最终速度还受 CPU、锁、连接池、网络和服务端容量影响。
为什么应该在 RunParallel 返回后 ReportMetric?
返回表示并行 body 已完成,此时读取计数和计时结果才是汇总状态;在 worker 内重复上报还会产生覆盖和竞争。
墨刀AI适合做数据看板原型吗?先验证指标层级、筛选和空状态
- 上一篇
- 墨刀AI适合做数据看板原型吗?先验证指标层级、筛选和空状态
- 下一篇
- Go 包初始化循环为什么在编译期被拒绝
-
- Golang · Go教程 | 46分钟前 | 时区 · Go教程 · time.Date · 夏令时 · 时间验证 · Go time.Date Go 夏令时日期验证 Go time.LoadLocation Go 重复小时 Go 时区偏移校验
- Go time.Date 跨夏令时生成日期时怎么验证
- 162浏览 收藏
-
- Golang · Go教程 | 58分钟前 |
- Go regexp.Expand 如何把捕获组写入缓冲区
- 468浏览 收藏
-
- Golang · Go教程 | 1小时前 | testing · Go教程 · benchmark · ReportMetric · 性能指标 · 基准测试 Go 自定义指标 testing.B ReportMetric
- Go testing.B ReportMetric 如何记录自定义指标
- 411浏览 收藏
-
- Golang · Go教程 | 2小时前 | 临时目录 Go并行测试 testing.T.TempDir
- Go testing.T TempDir 如何处理并行测试目录
- 251浏览 收藏
-
- Golang · Go教程 | 2小时前 |
- Go log/slog LogValuer 如何避免敏感字段展开
- 466浏览 收藏
-
- Golang · Go教程 | 2小时前 | go · 模板 · text/template · missingkey ·
- Go text/template Option missingkey 如何选择错误策略
- 204浏览 收藏
-
- Golang · Go教程 | 2小时前 |
- Go html/template URLQuery 如何安全拼查询参数
- 112浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 42次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 136次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 73次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 35次使用
-
- CMMLU
- 深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
- 23次使用
-
- Go语言自带测试库testing使用教程
- 2023-01-07 467浏览
-
- Go语言基础单元测试与性能测试示例详解
- 2023-01-07 426浏览
-
- 深入理解Golang的单元测试和性能测试
- 2023-01-07 374浏览
-
- Go error wrapping 实战:别让错误日志只剩一句 failed
- 2026-06-01 151浏览
-
- Go pprof 排查慢接口:别只会看火焰图,先把问题问对
- 2026-06-01 101浏览

