You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Goroutine是否必须运行在不同的CPU核心上?

为什么《Effective Go》示例中要按CPU核心数启动对应数量的goroutine

这个写法是CPU密集型计算场景下的效率优化选择,从来不是Go语言层面的强制要求,也和“goroutine不需要绑定独立CPU”的常识不冲突,核心逻辑非常直白:

  • 这个示例实现的是向量批量计算,属于没有任何IO、网络阻塞的纯CPU密集型任务,这类任务运行时会一直占住CPU时间片,不会主动让出调度权。如果启动的goroutine数量远大于实际可用的CPU核心数,Go调度器反而要频繁做goroutine上下文切换,平白消耗额外的CPU资源,拉低整体计算效率。按核心数等额启动goroutine,刚好能把每个核心的算力打满,同时把调度开销压到最低。
  • 这份示例编写的时期,Go运行时的GOMAXPROCS默认值就等于机器的CPU核心数,意味着调度层最多同时调度和核心数相等的goroutine并行执行,多开的CPU密集型goroutine只会在运行队列里排队等待调度,根本拿不到额外的并行收益。
  • 这个数量选择和文档末尾“并发不等于并行”的提醒也完全自洽:这个示例本身就是演示如何通过合理的并发结构,拿到多核并行的计算加速效果,按核心数分片只是为了最大化当前场景的执行效率,不是放之四海而皆准的规则。如果是IO密集型场景,比如大量请求数据库、调用外部接口的服务,goroutine数量远大于CPU核心数是非常正常的——毕竟这类场景下绝大多数goroutine都在等待IO返回,不会持续占用CPU资源,多开点反而能提升资源利用率。

文档中对应的示例代码如下:

const numCPU = 4 // number of CPU cores

func (v Vector) DoAll(u Vector) {
    c := make(chan int, numCPU)  // Buffering optional but sensible.
    for i := 0; i < numCPU; i++ {
        go v.DoSome(i*len(v)/numCPU, (i+1)*len(v)/numCPU, u, c)
    }
    // Drain the channel.
    for i := 0; i < numCPU; i++ {
        <-c    // wait for one task to complete
    }
    // All done.
}

对应文档原文的相关描述:

我们在循环中独立启动各个任务分片,每个CPU核心对应启动一个分片任务。任务完成顺序不固定,不会造成影响;启动全部goroutine后,只需排空channel内的完成信号即可确认所有任务执行完毕。

请务必不要混淆并发与并行的概念:并发是指将程序结构化为多个独立执行的组件,而并行是指为提升执行效率,在多个CPU上并行执行计算任务。

内容的提问来源于stack exchange,提问作者user19404305

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:18:18