
go test -cpu 参数到底控制什么
-cpu 不是让测试跑在指定 CPU 核心上,而是控制 runtime.GOMAXPROCS 的值——也就是 Go 调度器能同时执行用户级 goroutine 的 OS 线程数。它只影响测试期间的并发调度能力,和物理核心绑定无关。
- 值为
1,2,4时,分别对应GOMAXPROCS(1)、GOMAXPROCS(2)、GOMAXPROCS(4) - 多个值用逗号分隔(如
-cpu=1,2,4),会依次运行整套测试三次,每次用不同GOMAXPROCS - 若不指定,默认使用当前机器的逻辑 CPU 数(
runtime.NumCPU())
常见错误现象:以为加了 -cpu=8 就能“压满 8 核”,结果测试耗时没变化,甚至变慢——本质是测试本身没做并发操作,或瓶颈在 I/O、锁、内存分配上,而非调度器。
什么时候该用 -cpu 进行多配置测试
真正需要 -cpu 多值测试的场景很窄:你写的代码显式依赖 GOMAXPROCS 行为,或怀疑并发逻辑受调度策略影响。
- 典型例子:手写 goroutine 池、自定义 work-stealing 调度、用
runtime.LockOSThread()+ 多线程协作的底层封装 - 不适用的情况:普通 HTTP handler、数据库 CRUD、JSON 编解码等——它们的性能瓶颈不在调度层
- 性能影响:设得过小(如
-cpu=1)可能掩盖竞态;设得过大(如-cpu=64)若测试本身轻量,反而因调度开销增加总耗时
建议只在以下条件同时满足时启用多 -cpu 测试:
立即学习“go语言免费学习笔记(深入)”;
- 测试函数内启动了大量 goroutine(≥100)
- goroutine 之间有明确协作(如
sync.WaitGroup、chan同步) - 你修改过
GOMAXPROCS或依赖其默认行为
和 -race、-bench 结合使用的坑
-cpu 和 -race 可共存,但要注意:竞态检测器本身会显著拖慢执行,且对 GOMAXPROCS 更敏感。同一组 -cpu 值下,开启 -race 后可能暴露出平时看不到的 data race。
-
-bench默认不读取-cpu,必须显式加上-benchmem或指定-bench=.才生效 - 错误写法:
go test -bench=. -cpu=1,2,4→ 实际只用默认GOMAXPROCS跑 bench,-cpu被忽略 - 正确写法:
go test -bench=. -cpu=1,2,4 -benchmem,此时每组-cpu值都会独立跑一遍 benchmark
容易被忽略的一点:benchmark 函数里如果调用了 testing.B.ResetTimer() 或 testing.B.StopTimer(),它们不受 -cpu 影响,但计时逻辑可能因 goroutine 调度延迟而失真——尤其在 GOMAXPROCS=1 时,串行化效应会让单次迭代时间虚高。
替代 -cpu 的更直接压测方式
如果目标是真实多核压测(比如模拟高并发请求),-cpu 是错的工具。它改的是调度上限,不是负载强度。
- 真实压测应靠外部工具:
ab、hey、vegeta对本地 HTTP 服务发请求 - 或在测试中手动启多个 goroutine 并发调用目标函数,用
sync.WaitGroup控制并发数,再用time.Now()计时 - 若需观察 CPU 利用率,用系统命令:
top -p $(pgrep your_test_proc)或perf stat -e cycles,instructions,cache-misses
最常被忽略的复杂点:Go 的 GC 在高并发测试中会间歇 STW,导致吞吐波动。单纯调大 -cpu 可能让 GC 更频繁——这时该调 GOGC 或用 debug.SetGCPercent() 控制,而不是纠结调度参数。










