Go GMP 调度模型 · 分步交互演示

G = Goroutine(协程任务) M = Machine(内核线程) P = Processor(逻辑处理器,持有本地队列)。 点击「下一步」逐步观察调度器如何在全局队列 / 本地队列之间分发任务、执行 work stealing(工作窃取), 以及遇到阻塞系统调用时 M 与 P 如何解绑、重新绑定。演示固定 GOMAXPROCS = 4,简化了部分细节以突出核心机制。

G 状态 _Grunnable 排队中 _Grunning 执行中 _Gwaiting 等待中(park) _Gsyscall 系统调用阻塞 _Gdead 已完成 状态流转:_Grunnable →(调度器选中)→ _Grunning →(执行完成)→ _Gdead | _Grunning →(阻塞系统调用)→ _Gsyscall →(调用返回)→ _Grunnable | _Grunning →(park)→ _Gwaiting →(goready 唤醒)→ _Grunnable
M 状态 绑定 P 执行中 随 G 阻塞系统调用中 空闲缓存池中 状态流转:创建/复用 → 绑定 P 开始执行 →(G 阻塞系统调用 → 随 G 一起阻塞 | 本地+全局+可偷队列都空 → 释放为空闲)→ 被下一个 P 复用
P 状态 _Pidle 空闲(未绑定 M) _Prunning 运行中 _Psyscall 系统调用中(过渡态) 状态流转:_Pidle →(绑定 M 取到任务)→ _Prunning →(其上的 G 阻塞系统调用)→ _Psyscall(暂时仍与该 M 绑定)→(sysmon 判定超时执行 handoffp)→ _Pidle → 被绑定新 M 重新进入 _Prunning

🖱️ 把鼠标停留在任意 G / M / P 图形或队列区域上,会弹出它对应的 Go 运行时结构体(runtime.g / runtime.m / runtime.p / runtime.schedt)当前字段值。

⌨️ 快捷键:空格 暂停/播放  上一步  下一步(自由体验模式下 为单步调度,没有"上一步")。

固定的 12 步剧本,用「上一步 / 下一步 / 自动播放」按顺序讲解一次典型调度过程。

全局队列 Global Run Queue
系统调用阻塞区 Syscall
空闲 M 缓存池 Idle M Cache
已完成 0 / 8
播放速度
步骤 1 / 12

事件日志 EVENT LOG