当前位置: 首页 > news >正文

深入 Go 底层原理(四):GMP 模型深度解析

1. 引言

在上一篇文章中,我们宏观地了解了 Go 的调度策略。现在,我们将深入到构成这个调度系统的三大核心组件:GMP。理解 GMP 模型是彻底搞懂 Go 并发调度原理的关键。

本文将详细解析 G、M、P 各自的职责以及它们之间是如何协同工作的。

2. GMP 核心组件
  • G (Goroutine):

    • 定义:G 就是我们常说的 Goroutine。它是一个待执行的任务单元,包含了执行所需的栈空间指令指针 (PC) 以及其他状态信息(如 goroutine status)。

    • 特点:G 是轻量级的,初始栈大小仅为 2KB,可以根据需要动态伸缩。Go 程序可以轻松创建成千上万个 G。

    • 状态:G 有多种状态,如 _Gidle (闲置), _Grunnable (可运行), _Grunning (运行中), _Gsyscall (系统调用中), _Gwaiting (等待中), _Gdead (已死亡) 等。调度器根据这些状态来移动 G。

  • M (Machine):

    • 定义:M 是内核线程的抽象,是真正执行代码的实体。runtime 会限制 M 的数量,默认不超过 10000。

    • 职责:M 从一个关联的 P 的本地队列中获取 G,然后执行 G 的代码。如果 G 发生系统调用或阻塞,M 可能会与 P 解绑。

    • M0MM0是主线程,是程序启动时创建的第一个内核线程。

  • P (Processor):

    • 定义:P 是处理器的抽象,它代表了 M 执行 Go 代码所需的上下文资源。P 的数量在程序启动时被设置为 GOMAXPROCS 的值,通常等于 CPU 的核心数。

    • 职责:P 是 G 和 M 之间的“中间人”。它维护一个本地可运行 G 队列 (LRQ),为 M 提供可执行的 G。P 的存在使得调度器可以控制并发的程度(即同时有多少个 G 在真正地运行)。

    • 关键作用:P 的引入实现了 M 和 G 的解耦。当一个 M 因为其上运行的 G 进行系统调用而阻塞时,P 会从这个 M 上解绑,并去寻找一个空闲的 M(或创建一个新的 M)来继续执行自己队列中的其他 G。这使得 Go 的并发能力不会因为部分 Goroutine 的阻塞而受限。

3. GMP 的协作流程

一个典型的调度场景如下:

  1. 启动:程序启动,创建 M0,并创建 GOMAXPROCS 个 P。

  2. G 的创建go func() 创建一个新的 G。这个新的 G 会被优先放入当前 M 绑定的 P 的本地队列 (LRQ) 的队头。

  3. M 的执行循环

    • M 启动后,会绑定一个 P(acquirep)。

    • M 进入一个无限的调度循环 (schedule)。

    • 在循环中,M 尝试从 P 的 LRQ、全局队列 (GRQ) 或通过工作窃取 (runqsteal) 来获取一个可运行的 G。

    • 找到 G 后,M 会执行 G 的代码 (execute)。

    • G 执行完毕后,M 会再次进入调度循环寻找下一个 G。

  4. 系统调用场景 (Syscall):

    • 假设 M0 上的 G0 准备进行一个会阻塞的系统调用。

    • M0 会与它的 P0 解绑

    • P0 会去寻找一个空闲的 M(比如 M1)或者创建一个新的 M1。

    • P0 会绑定到 M1 上,并继续执行 P0 本地队列中的其他 G。

    • 与此同时,原来的 M0 则陷入系统调用,等待其完成。

    • 当 G0 的系统调用结束后,它会尝试获取一个空闲的 P 来继续执行。如果获取不到,G0 会被放入全局队列。M0 则会进入休眠。

这个设计使得 P(并发的许可证)不会因为 M 的阻塞而被浪费,从而保证了 GOMAXPROCS 个 Goroutine 可以持续地、并行地运行。

4. sysmon 监控线程

除了 G, M, P,还有一个重要的后台角色:sysmon。它是一个由 runtime 启动的、不需要 P 的 M,在后台执行以下任务:

  • 抢占:如上篇所述,向运行时间过长的 G 发送抢占信号。

  • 网络轮询 (netpoller):检查网络 I/O 是否就绪,并唤醒因此阻塞的 G。

  • GC 辅助:在需要时触发 GC。

  • 释放闲置资源:定期将长时间空闲的 M 和 P 的资源回收。

5. 总结

GMP 模型是 Go 语言高性能并发调度的核心。

  • G 是任务单元。

  • M 是执行实体(内核线程)。

  • P 是调度上下文和资源的提供者,是实现 M:N 模型的关键。

它们通过工作窃取、系统调用处理、异步抢占等机制紧密协作,构成了一个强大、高效、自适应的调度系统。

http://www.lryc.cn/news/607941.html

相关文章:

  • 深入 Go 底层原理(八):sync 包的实现剖析
  • 中科院自动化所机器人视觉中的多模态融合与视觉语言模型综述
  • Python 程序设计讲义(54):Python 的函数——函数概述
  • Java 集合框架: LinkedHashSet
  • innoDB的buffer pool
  • API征服者:Python抓取星链卫星实时轨迹
  • k8s集群部署(脚本版)
  • 【CVPR2025】计算机视觉|即插即用|GCNet:炸裂!实时语义分割新星GCNet,性能速度双突破!
  • 前端应用权限设计面面观
  • JVM中的垃圾回收暂停是什么,为什么会出现暂停,不同的垃圾回收机制暂停对比
  • 题解:P4447 [AHOI2018初中组] 分组
  • rabbitmq消息队列详述
  • python创建一个excel文件
  • PHP 与 MySQL 详解实战入门(2)
  • Removing Digits(Dynamic Programming)
  • 【第三章】变量也疯狂:深入剖析 Python 数据类型与内存原理
  • Android13文件管理USB音乐无专辑图片显示的是同目录其他图片
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博舆情数据可视化分析-热词情感趋势柱状图
  • 机器学习 —— 决策树
  • 从C++0基础到C++入门(第十五节:switch语句)
  • 计算机网络:为什么IPv6没有选择使用点分十进制
  • 如何修复非json数据
  • Gemini CLI
  • 深入 Go 底层原理(五):内存分配机制
  • 操作系统-lecture5(线程)
  • Vue3核心语法基础
  • 【大模型入门】3.从头实现GPT模型以生成文本
  • 相对路径 绝对路径
  • UniappDay07
  • sqli-labs:Less-19关卡详细解析