GPM 模型中为什么 P 的数量默认等于 CPU 核心数?

GPM 是 Go 的用户态协程调度模型,核心是绕开内核态线程调度的高开销,由 Go 运行时自主管理协程(G)与内核线程(M)的映射,实现轻量高效的多核并行。P 解耦了 G 和 M 的直接关联,GOMAXPROCS 控制 P 的数量(默认等于 CPU 核心数),P 的数量决定了 Go 程序同时并行执行 G 的最大数(多核并行的核心)。

CPU 是硬件,P 是 Go 运行时机制在软件层面的抽象。GMP 模型中,一个 P 对应一个 CPU 核心,Go 的核心诉求是让 G 能在多核 CPU 上真正并行执行,同一时间,一个 P 只能绑定一个 M(内核态线程,真正干活儿的),而一个 M 只能跑在一个 CPU 核心上,所以 P 的数量设为 CPU 核心数时,能保证 Go 程序同时有和 CPU 核心数相同的 M 在并行执行 G,刚好把所有 CPU 核心的计算能力占满。

比如我的电脑是 4 核 CPU,GOMAXPROCS默认是 4,Go 运行时就会创建 4 个 P,最多同时有 4 个 M 绑定 P, 跑在 4 个 CPU 核心上,执行 4 个 G,实现多核并行。

P≠CPU

比如你是 8 核 CPU,手动设置GOMAXPROCS=4,Go 运行时只会创建 4 个 P,哪怕有 8 个 CPU 核心,Go 程序最多也只能同时跑 4 个 M 执行 G,剩下的 4 个 CPU 核心 Go 程序不会去用(除非其他进程占用)。

反过来,若你是 4 核 CPU,硬把GOMAXPROCS=8,Go 会创建 8 个 P,但因为只有 4 个物理 CPU 核心,8 个 P 绑定的 8 个 M 会被操作系统调度到 4 个 CPU 上并发执行(不是并行),反而会因为操作系统的线程切换产生额外开销,拖慢程序。

如果没有 P,G 直接绑定 M,M 直接跑在 CPU 上,G 一旦阻塞,M 就会被操作系统挂起,对应的 CPU 核心就会空闲,而有了 P 后,G 阻塞时 M 和 P 解绑,P 可以立刻绑定新的 M,继续利用 CPU 核心执行其他 G,让 CPU 核心始终有活干,这就是 GPM 模型高效的核心原因。

M 必须绑定 P,才能拿到 P 代表的 CPU 执行资源,进而执行 G,三者的链路是:G → P(持资源 + 管队列) → M(内核线程) → CPU(物理计算)。P 的存在,让 Go 绕开操作系统的内核调度,能够更好的提升 CPU 的使用效率。

Copyright © 2026 晋坤 的博客. All Right Reserved.