0

0

GMP调度模型到底是怎么回事?手绘图解最全版

舞夢輝影

舞夢輝影

发布时间:2026-01-23 14:35:34

|

212人浏览过

|

来源于php中文网

原创

GMP调度模型是Go运行时的用户态并发调度机制,由G(goroutine)、M(OS线程)、P(逻辑处理器)协同实现高效复用与负载均衡。

gmp调度模型到底是怎么回事?手绘图解最全版

GMP调度模型是Go语言运行时实现并发的核心机制,它用三个关键角色(G、M、P)协同工作,让成千上万个goroutine能在少量操作系统线程上高效、公平地运行。它不是操作系统级的调度,而是Go自己在用户态做的“二次调度”,目标是减少系统调用开销、提升CPU利用率、隐藏I/O等待时间。

三个主角:G、M、P 分别是什么?

G(Goroutine):轻量级协程,Go里的并发执行单元。每个G只占2KB空间(可动态伸缩),创建销毁成本极低。它不绑定线程,只保存自己的执行上下文(如PC、栈指针、寄存器等)。

M(Machine):对应一个OS线程(比如Linux上的pthread)。M负责真正执行G的代码。M数量默认无硬上限,但受P数量和阻塞操作影响——当M因系统调用或锁等待而阻塞时,Go运行时会尝试复用其他M。

P(Processor):逻辑处理器,是G调度的关键枢纽。P的数量默认等于CPU核心数(可通过GOMAXPROCS设置),它持有:
• 本地G队列(最多256个,FIFO)
• 全局G队列(所有P共享,有锁
• 可运行G的“所有权”——只有拥有P的M才能执行G
• 内存分配缓存(mcache)、垃圾回收状态等

调度是怎么流动起来的?

一个G从诞生到执行,经历典型的“入队→获取P→被M执行→可能让出/阻塞→再调度”过程:

  • 新G创建后,优先加入当前P的本地队列;若本地队列满,则入全局队列
  • M需绑定一个P才能运行G:启动时抢一个空闲P;若M阻塞(如syscall),会释放P供其他M使用
  • M从自己绑定的P中按顺序取G执行;若本地队列空,先尝试从全局队列偷一批(至少1/4),再尝试“工作窃取”(steal)——从其他P的本地队列尾部偷一半
  • G主动让出(如调用runtime.Gosched())、被抢占(如超过10ms的连续运行,由sysmon线程触发)、或进入阻塞(如channel收发、网络读写、time.Sleep),都会触发调度器介入,保存现场并寻找下一个可运行G

几个关键设计细节,决定它为什么快又稳

非抢占式 + 有限抢占:Go早期完全协作式,现在通过sysmon监控线程,对长时间运行的G强制插入抢占点(如函数入口、循环回边),避免某个G饿死其他G。

知料万语
知料万语

知料万语—AI论文写作,AI论文助手

下载

系统调用处理巧妙:M进入阻塞系统调用前,会将P解绑并转入自旋状态(尝试找新M接管);调用返回后,M优先尝试重新获取原P;失败则把G放回全局队列,自己休眠——避免P空转、也避免M堆积。

内存与GC友好:每个P自带mcache,小对象分配无需锁;GC的三色标记也以P为单位并发扫描,提升停顿控制能力。

一张图看懂核心流转(文字版示意)

(想象手绘草图结构)
顶部:多个P(P0, P1, P2…)并排,每个P下挂一个“本地G队列”(竖列小方块G1-G5)
中间:若干M(M0-M3)箭头指向各自绑定的P;M0正在执行P0的G1,M1空闲等待P,M2卡在syscall(画个云朵标“阻塞中”)
底部:一个“全局G队列”+“netpoller”(处理异步网络事件)+“sysmon”(小哨兵图标,监视M和G)
箭头穿插:G从全局队列→P本地队列;M从P偷G;阻塞M释放P→空闲M抢P;sysmon向G发送抢占信号

不复杂但容易忽略:GMP不是静态绑定,而是一套动态借还、平衡负载的协作协议。理解它,能帮你写出更少竞争、更低延迟、更易诊断的Go并发代码。

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

Go中Type关键字的用法
Go中Type关键字的用法

Go中Type关键字的用法有定义新的类型别名或者创建新的结构体类型。本专题为大家提供Go相关的文章、下载、课程内容,供大家免费下载体验。

234

2023.09.06

go怎么实现链表
go怎么实现链表

go通过定义一个节点结构体、定义一个链表结构体、定义一些方法来操作链表、实现一个方法来删除链表中的一个节点和实现一个方法来打印链表中的所有节点的方法实现链表。

446

2023.09.25

go语言编程软件有哪些
go语言编程软件有哪些

go语言编程软件有Go编译器、Go开发环境、Go包管理器、Go测试框架、Go文档生成器、Go代码质量工具和Go性能分析工具等。本专题为大家提供go语言相关的文章、下载、课程内容,供大家免费下载体验。

249

2023.10.13

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.7万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号