知识卡片
窃取平衡负载
内容
当本地、全局和网络队列都找不到任务时,P 会从其他 P 的本地队列偷取一半任务。工作窃取让负载自动扩散,减少中心化调度锁竞争。
结构图:
flowchart LR
A[空闲 P] --> B{本地队列为空}
B -->|是| C[查看全局队列]
C --> D{仍无任务}
D -->|是| E[从其他 P 窃取一半 G]
E --> F[恢复执行负载]
参考来源
- 位置:《Go语言底层原理剖析》第15章《深入协程设计与调度原理》15.5.4节《协程窃取》
- 结论依据:原文说明"当局部运行队列、全局运行队列以及准备就绪的网络列表中都找不到可用协程时,需要从其他P的本地队列中窃取可用的协程执行",并用 findrunnable 函数中"随机遍历allp数组,找到可用的P就立即窃取"及 runqgrab 函数"将要窃取的P本地运行队列中Goroutine个数的一半放入自己的运行队列中",因此可以推出"空闲 P 会从其他 P 随机窃取一半任务来平衡负载"的结论。
- 原始内容:当局部运行队列、全局运行队列以及准备就绪的网络列表中都找不到可用协程时,需要从其他P的本地队列中窃取可用的协程执行……第2层for循环表示随机遍历allp数组,找到可窃取的P就立即窃取并返回……找到要窃取的P之后就正式开始窃取了,其核心代码位于runqgrab函数。窃取的核心逻辑比较简单……将要窃取的P本地运行队列中Goroutine个数的一半放入自己的运行队列中。