Post

GMP

GMP

GMP 概念

参考资料

GMP 是 Go 运行时调度器的核心模型,三者分工明确:

组件 英文全称 中文释义 核心定位
G Goroutine 协程 用户态执行单元(业务逻辑载体)
M Machine 操作系统线程 真正执行代码的内核实体
P Processor 逻辑处理器 调度上下文 / 资源管理器(核心枢纽)

注意:P 并非硬件 CPU,而是 Go 运行时抽象的 “执行许可证”,核心资源是本地 G 队列、调度规则、M 绑定权、内存缓存(MCache),而非线程的栈 / 寄存器 / 堆(栈归 G、寄存器归 M、堆归全局内存管理器)。

G-M关系

G 必须依附于 M 才能执行,二者是协程与线程的核心绑定关系:

执行环境

  • M(线程):由操作系统分配,拥有内核级资源(栈、寄存器、文件句柄等),是 CPU 上执行代码的 “实体”;
  • G(协程):用户态轻量级执行单元,无独立内核资源,必须绑定到 M 上才能运行。
1
2
3
4
5
6
// 简化的绑定逻辑(Go运行时源码核心逻辑)
mp.curg = gp  // M绑定当前执行的G
gp.m = mp     // G关联所属的M
// G执行完毕后解绑,M从队列取下一个G继续执行
mp.curg = nil
gp.m = nil

数量关系

  1. 数量对比:G 的数量远大于 M(G 可轻松创建数万 / 数十万,M 数量受 CPU 核心数约束,默认不超过GOMAXPROCS);
  2. 绑定规则:
    • 一对一:同一时间,一个 M 只能执行一个 G,一个 G 也只能被一个 M 执行;
    • 多对一:多个 G 可轮流绑定同一个 M 执行(调度器切换)

GMP 协作关系

通俗类比

组件 类比 角色说明
P 工位 提供 “干活资格”+ 存放待办任务
M 工人 有 “工位(P)” 才能干活
G 任务 待执行的具体工作

协作逻辑

1
2
3
4
5
6
7
8
9
10
┌─────────┐
│    M    │ ----> 绑定 ──> ┌─────────┐
│  线程   │                │    P    │
└─────────┘               │ 逻辑处理器│
                          └─────────┘
                                │ 维护本地可运行G队列
                                ▼
                        ┌───G───G───G───G───┐
                        │  协程1 协程2 协程3  │
                        └────────────────────┘

关键规则:

  1. M 依赖 P:M 必须先绑定 P 才能执行 G(无 P 的 M 会进入休眠,释放 CPU 资源);
  2. P 管理 G 队列:P 优先维护本地 G 队列(非全局队列),减少全局竞争;仅当本地队列为空时,P 才会从全局队列 / 其他 P 的本地队列 “偷取” G;
  3. P 的资源协调:当 G 发起系统调用时,P 会与当前 M 解绑,转而绑定其他空闲 M,保证 CPU 不空闲(Go 高并发的核心设计);
  4. G 的调度:P 按照时间片、抢占规则调度本地队列的 G,让多个 G 在同一个 M 上 “并发” 执行。

总结

  1. P 是 “逻辑处理器” 而非硬件 CPU,核心资源是本地 G 队列、调度上下文、M 绑定资格;
  2. G 依赖 M 执行,M 依赖 P 获得执行资格,P 是调度层面的 “资源协调者”;
  3. P 的本地队列设计 + G 偷取机制,是 Go 调度器高效利用 CPU 的关键。
This post is licensed under CC BY 4.0 by the author.