419 字
2 分钟
Golang GMP 调度器详解:Go 语言高并发的内核

协程 (Coroutine) 的复兴#

在 Go 语言出现之前,高并发要么靠多进程(PHP),要么靠多线程(Java),要么靠异步回调(Node.js)。 Go 选择了 M 调度模型,把并发的复杂度藏在了 Runtime 里。

GMP 模型#

  • G (Goroutine):协程。包含栈、指令指针等。初始栈只有 2KB。
  • M (Machine):内核线程 (OS Thread)。真正执行代码的劳工。
  • P (Processor):逻辑处理器。代表 CPU 核心。它维护了一个本地队列 (Local Run Queue)。

调度流程#

  1. M 绑定 P:线程 M 必须拿到 P 才能执行 G。
  2. 本地队列:新创建的 G 优先放在 P 的本地队列,无锁,速度快。
  3. 全局队列:如果本地满了,放在全局队列(需要加锁)。
  4. Work Stealing (窃取):如果 P 的本地队列空了,它会去偷其他 P 的一半 G 过来运行。这就保证了所有 CPU 核心都不会闲着。

系统调用 (Syscall)#

当 G 进行系统调用(如文件 IO)阻塞时:

  1. P 会和 M 分离 (Handoff)。P 去找一个新的 M(或者新建一个)继续运行其他的 G。
  2. 旧的 M 陪着那个阻塞的 G 等待。
  3. 这就避免了整个线程被阻塞导致 CPU 浪费。

抢占式调度#

在 Go 1.14 之前,如果一个 G 写了死循环,它会霸占 P,其他 G 饿死。 现在,Go 引入了 基于信号的抢占。 Runtime 会向线程发送信号,强行中断 G 的执行,把它踢回队列。

总结#

Goroutine 使得“每请求一线程”成为可能。 你只管 go func(),剩下的交给 GMP。 这是 Go 语言称霸云原生领域的基石。

Golang GMP 调度器详解:Go 语言高并发的内核
https://www.oferry.com/posts/a63/
作者
晨平安
发布于
2026-02-10
许可协议
CC BY-NC-SA 4.0
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00