如何理解 Go 的调度模型,以及 G / M / P 各自的职责

一、为什么需要调度模型?

先问一个问题:

Go 里可以同时开成千上万个 goroutine,它是怎么做到的?

如果每个 goroutine 都对应一个操作系统线程,那系统早就炸了。

因为:

  • 线程很重(几 MB 栈空间)
  • 创建销毁成本高
  • 线程切换开销大

所以 Go 自己实现了一套“用户级调度器”。


二、Go 的整体调度模型(GMP 模型)

Go 使用的是:

G - M - P 调度模型

可以理解为:

G(任务)
M(干活的工人)
P(调度中心 / 工作许可证)

一个简单类比:

现实世界 Go 中
任务 G (goroutine)
工人 M (machine 线程)
工头 / 任务队列管理 P (processor)

三、G / M / P 分别是什么?


1️⃣ G —— Goroutine(真正的任务)

G 就是:

你写的每一个 goroutine

例如:

go func() {
    fmt.Println("hello")
}()

这就是创建了一个 G。

G 里面包含什么?

  • 要执行的函数
  • 栈空间(初始 2KB,可自动扩容)
  • 程序计数器
  • 状态(运行中、等待中等)

G 是“轻量级线程”。


2️⃣ M —— Machine(真正干活的线程)

M 是:

操作系统线程

它是真正执行代码的“工人”。

⚠️ 注意:

  • M 是系统线程
  • 是 OS 创建的
  • 真正跑 CPU 的是 M

3️⃣ P —— Processor(最关键)

P 是整个模型的核心。

P 是:

调度器的资源控制单元

它负责:

  • 管理本地 G 队列
  • 把 G 分配给 M 执行
  • 维护调度状态

可以理解为:

M 想干活,必须拿到 P


四、三者关系图

一个简化关系:

G → 被放入 → P 的本地队列
M → 必须绑定 → P
M + P → 才能执行 G

执行流程:

1. 创建 G
2. G 放入某个 P 的队列
3. M 绑定 P
4. M 从 P 队列取 G
5. 执行 G

五、为什么要有 P?

很多人问:

为什么不直接 G + M?

因为:

如果只有 G 和 M:

  • 所有 goroutine 共享一个全局队列
  • 频繁加锁
  • 性能差

加入 P 之后:

每个 P 有:

  • 本地 G 队列(减少锁竞争)
  • 运行中的 G

优点:

  • 降低锁竞争
  • 提高 CPU 利用率
  • 更好扩展到多核

六、数量关系

默认情况下:

P 的数量 = CPU 核心数

可以通过设置:

runtime.GOMAXPROCS(n)

来修改 P 的数量。


七、完整调度过程(一步一步)

假设有 4 核 CPU:

P0  P1  P2  P3

1️⃣ 创建 goroutine
→ 放进某个 P 的本地队列

2️⃣ M 绑定 P
→ 每个 P 同时只能被一个 M 使用

3️⃣ M 从 P 队列取 G
→ 执行

4️⃣ 如果队列空了?
→ 去别的 P 偷任务(Work Stealing)


八、Work Stealing(工作窃取)

这是 Go 调度器非常重要的机制。

如果:

P0 很忙
P1 没活干

P1 会:

从 P0 的队列“偷一半任务”过来

这样可以:

  • 保证负载均衡
  • 提高 CPU 利用率

九、阻塞时会发生什么?

比如:

time.Sleep()
网络 IO
channel 阻塞

当 G 阻塞时:

  1. M 不会一直等
  2. M 会解绑当前 P
  3. P 会找别的 M 继续干活

这样不会浪费 CPU。


十、总结一句话理解 GMP

可以记住这个公式:

G 是任务
M 是执行者
P 是调度资源
M 必须拿到 P 才能执行 G

再简化:

G = 干什么
M = 谁干
P = 批准干 + 排队系统

十一、面试级总结版本

如果你以后面试,可以这样回答:

Go 使用 GMP 调度模型。

G 表示 goroutine,是待执行的任务。
M 是操作系统线程,真正执行代码。
P 是调度资源,维护本地 goroutine 队列。

M 必须绑定 P 才能执行 G。

Go 通过本地队列 + 工作窃取算法,实现高效并发调度。


十二、给编程小白的最终理解图

你可以在脑中想象:

CPU核心数量 = P数量
每个P都有一个任务仓库
M是工人
G是任务
工人必须拿到一个仓库许可(P)
才能从仓库拿任务干活
posted @ 2026-02-07 21:30  牛奔  阅读(29)  评论(0)    收藏  举报