Copied
Please follow the site license
报告
章节_文章 // 现场报告

文章编号: RL-GOLANG的G

2026.06.18

Golang 的 GMP 原理

Chavy
Chavy
#Go#GMP#Concurrency
分析

摘要:深入剖析 Go 语言的协程调度 GMP 模型,理解其进程、线程、协程与 Goroutine 的关系和调度原理。

概念梳理#

进程#

进程是计算机中已运行的程序示例,拥有独立的内存空间、资源和系统信息。每个进程都是互相独立的,进程间通信需要通过特定的机制(如管道、消息队列、共享内存、信号、套接字、信号量、内存映射文件、远程过程调用(RPC)等),核心点如下:

(1)独立的内存空间

(2)进程之间相互隔离

(3)创建和销毁开销较大

(4)通常用于操作系统调度的基本单位

线程#

通常语义中的线程,指的是内核级线程,核心点如下:

(1)是操作系统最小调度单元

(2)创建、销毁、调度交由内核完成,cpu 需要完成用户态与内核态的切换

(3)可充分利用多核,实现并行

协程#

协程,又称为用户级线程,核心点如下:

(1)与线程存在映射关系,为 M:1

(2)创建、销毁、调度在用户态完成,对内核透明,所以更轻

(3)从属同一个内核级线程,无法并行;一个协程阻塞会导致从属同一下称的所有协程无法执行

Goroutine#

Goroutine,经 Golang 优化后的特殊”协程“,核心点如下:

(1)与线程存在映射关系,为 M;

(2)创建、销毁、调度都在用户态完成,对内核透明,足够轻便

(3)可以利用多线程、实现并行

(4)通过调度器的斡旋,实现和线程间的动态绑定和灵活调度

(5)栈空间大小可动态扩缩,因地制宜

GMP 模型#

g#

  • g,即 goroutine,是 golang 中对协程的抽象
  • g 有自己的运行栈、生命周期状态、以及执行的任务函数(用户通过 go func 指定);
  • g 需要绑定在 m 上执行,在 g 视角中,可以将 m 理解为它的 cpu

m#

  • m 即 machine,是 golang 中对线程的抽象
  • m 需要和 p 进行结合,从而进入 gmp 调度体系之中
  • m 的运行目标始终在 g0 和 g 之间切换-当运行 g0 是执行的是 m 的调度流程,负责寻找合适的”任务“,也就是 g;当运行 g 时,执行的时 m 获取到的”任务“,也就是用户通过 go func 启动的 goroutine

p#

  • p 即 processor,是 golang 中的调度器
  • p 可以理解为 m 的执行代理,m 需要与 p 绑定后,才会进入到 gmp 调度模式中;因此 p 的数量决定了 g 最大并行数量(可由用户通过 **GOMAXPROCS** 进行设定,超过 CPU 核数时无意义)
  • p 是 g 的存储容器,其自带一个本地 g 队列(local run queue,简称 lrq),承载着一系列等待被调度的 g

gmp#

(1)M 是线程的抽象;G 是 goroutine;P 是承上启下的调度器

(2)M 调度 G 前,需要和 P 绑定

(3)全局有多个 M 和多个 P,但同时并行的 G 的最大数量等于 P 的数量

(4)G 的存放队列有三类:P 的本地队列、全局队列和 wait 队列

(5)M 调度 G 时,优先取 P 本地队列,其次取全局队列,后取 wait 队列,这样的好处是,取本地队列时,可以接近于无锁化,减少全局锁竞争

(6)为防止不同 P 的闲忙差异过大,设立 work-stealing 机制,本地队列为空的 P 可以尝试从其他 P 本地队列偷取一半 G 补充到自身队列中

R P
莱茵实验室先锋部
认证_已验证: 2026.06.18
// 文章结束

Subscribe

Subscribe via RSS to receive notifications when new posts are published.

Follow
Classified
章节_06
协议编号: CC-BY-NC-SA-4.0

Golang 的 GMP 原理

作者:CHONGXI发布日期:2026.06.18

基于 CC BY-NC-SA 4.0

05 // 传输日志记录

© 2025-2026 Lonetrail
Powered by Astro & Lonetrail 非协作实体 // 协议_V.4.21