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

news/2026/4/16 16:35:07/文章来源:https://www.cnblogs.com/niuben/p/19589786

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

先问一个问题:

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)
才能从仓库拿任务干活

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/808114.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

效果比较好的生发机构推荐-黑奥秘以慢病管理打造毛发养护体系

据有关数据显示,我国有超过2.5亿人正面临着严重的毛发健康问题,且呈现年轻化趋势。现在脱发与白发问题已不再是简单的美容困扰,而被纳入慢病管理的范畴,头发问题病程周期长、发展缓慢,易反复,对身心状态均会产生…

盒马鲜生礼品卡回收时需要注意哪些问题呢? - 京顺回收

在消费场景日益多元的当下,盒马鲜生礼品卡因门店调整、消费习惯改变等因素,闲置率超过35%。如何安全高效地完成回收,成了用户关注的重点。结合行业数据与权威平台操作案例,以下梳理出盒马鲜生礼品卡回收的五大核心…

【小程序毕设全套源码+文档】基于Android的大学生勤工助学管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

MoeCTF-web23详解

readobject-->?-->rce 我们的rce经典模板 import org.apache.commons.collections.functors.InvokerTransformer;import java.lang.reflect.Method;public class test {public static void main(String[] args)…

Java面向对象——接口

Java面向对象——接口接口 普通类:只有具体实现 抽象类:具体实现和规范(抽象方法)都有 接口:只有规范,无法自己写方法,实现约束 约束和实现分离 //类中 //抽象类:extends //类 可以实现接口 implements 接口 /…

生发养发馆哪家效果好?黑奥秘全周期管理,契合毛发慢病养护逻辑

有数据显示,我国脱发白发人群近5亿,毛发问题正式纳入慢病管理范畴,病程长、易反复、需动态干预。黑奥秘专注脱发白发理疗19年品牌,以“检测建档-动态干预-身心同治-定期随访”的慢病管理模式为核心,依托智能检测C…

基于卷积神经网络的地震数据破碎带识别方法研究-大数据深度学习算法毕设毕业设计项目PyQT

博主介绍:👉全网个人号和企业号粉丝40W,每年辅导几千名大学生较好的完成毕业设计,专注计算机软件领域的项目研发,不断的进行新技术的项目实战👈 ⭐️热门专栏推荐订阅⭐️ 订阅收藏起来,防止下次找不到 &am…

基于机器学习的眼底图像糖尿病视网膜病变诊断系统-大数据深度学习算法毕设毕业设计项目PyQt

博主介绍:👉全网个人号和企业号粉丝40W,每年辅导几千名大学生较好的完成毕业设计,专注计算机软件领域的项目研发,不断的进行新技术的项目实战👈 ⭐️热门专栏推荐订阅⭐️ 订阅收藏起来,防止下次找不到 &am…