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

为什么Golang调度器使用全局运行队列和本地运行队列管理goroutine?

为什么Go运行时调度器要用全局+本地两个队列管理Goroutine?

我在研究Go内部管理Goroutine的机制时,发现运行时调度器用两个队列来管理已创建的Goroutine:

  • 全局运行队列(Global run queue):所有新建的Goroutine都会被放入这个队列
  • 本地运行队列(Local run queue):即将运行的Goroutine会被分配到这里,调度器从本地队列把Goroutine分配给OS线程

我的问题是:为什么调度器要搞两个队列?只用全局队列直接映射到OS线程不行吗?


核心原因:性能与调度效率的平衡

1. 减少全局锁竞争

如果所有Goroutine都塞进全局队列,每个OS线程(M)每次取Goroutine都得争抢全局锁,高并发场景下锁竞争会严重拖慢性能。本地队列属于每个逻辑处理器(P),当P绑定M时,操作本地队列不需要全局锁,只有在本地队列空了去全局队列取、或者全局队列需要补充Goroutine时才会触发全局锁操作,能大幅降低锁冲突的概率。

2. 利用CPU缓存局部性

Goroutine的栈和调度相关信息如果一直在同一个P对应的M上运行,能更好地利用CPU的各级缓存(比如L1/L2缓存)。如果只用全局队列,Goroutine可能被随机分配到不同的M,缓存命中率会急剧下降,整体运行效率大打折扣。本地队列让Goroutine尽量在同一个P的上下文里执行,最大化缓存复用的收益。

3. 实现高效负载均衡

当某个P的本地队列空了,它会启动工作窃取机制:去其他P的本地队列偷取一半的Goroutine过来执行。这种去中心化的负载分配方式,比所有M都盯着全局队列抢要高效得多。如果只有全局队列,很容易出现部分M空闲、部分M过载的不均衡情况,调度效率低下。

4. 适配Go的G-M-P调度模型

Go的调度器基于G-M-P模型设计:G是Goroutine,M是OS线程,P是逻辑处理器(负责管理调度上下文和本地队列)。本地队列是P的核心组成部分,把Goroutine和P绑定后,M在绑定P时能快速拿到可执行的Goroutine,避免每次都去全局队列查找,完美适配了整个调度模型的高效运转逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 03:40:18