Skip to content

调度内核:工作窃取算法

源:CoroutineScheduler 内部原理

Kotlin 协程在 JVM 上的默认调度器(DefaultIO)由一个高效的 CoroutineScheduler 驱动。它采用了 工作窃取 (Work-Stealing) 算法,极大地提高了 CPU 利用率。

架构模型

调度器维护了两级任务队列:

  1. 本地队列 (Local Queue): 每个工作线程 (Worker) 都拥有一个私有的、固定大小(通常是 128)的环形队列。访问这个队列不需要加锁(或极少的 CAS)。
  2. 全局队列 (Global Queue): 一个无限容量的并发安全队列。当本地队列满时,或者动态注入新任务时,任务会进入这里。

工作窃取流程

当一个 Worker 线程完成了手中的任务,它会按照以下顺序寻找新工作:

  1. Local Poll: 尝试从自己的本地队列队头取出任务。 (最快,无竞争)
  2. Global Poll: 如果本地为空,尝试从全局队列窃取一批任务放到本地。
  3. Work Stealing: 如果全局也为空,它会随机选择另一个 "受害者" (Victim Worker),试图从它的本地队列队尾 "偷" 一半的任务。

::: mermaid graph LR WorkerA[空闲 Worker A] -- 1. 也是空的 --> LocalA[A 的本地队列] LocalA -- 2. 也是空的 --> Global[全局队列] Global -- 3. 偷! --> LocalB[繁忙 Worker B 的本地队列] LocalB -- 拿走 50% 任务 --> WorkerA :::

BLOCKING 模式

为了支持 IO 操作,调度器支持线程动态扩容。 当协程执行阻塞代码(如 IO 调度器中)时,Worker 线程会标记自己为 BLOCKING。此时,调度器会检查是否需要创建一个新的 Worker 线程来维持 CPU 核心数的并发计算能力。

  • 默认上限:64 个线程。
  • 可通过 JVM 参数调整。