golang GMP模型
概述
G — 表示 Goroutine,它是一个待执行的任务;
M — 表示操作系统线程,它由操作系统的调度器调度和管理,实际承载goroutine的运行;
P — 表示逻辑处理器,它可以被看做运行在线程上的本地调度器。
M:N模型
Runtime 会在程序启动的时候,创建 M 个线程(CPU 执行调度的单位),之后创建的 N 个 goroutine 都会依附在这 M 个线程上执行。
- P先从自己的本地runnable queue找一个G
- 要是没找到,就去别的P上找
- 没找到就去Global runnable queue找
- 还没找到就要去network poller中找阻塞在网络请求中的G
此外, 每61次会强行去 Global runnable queue 找 G
- Goroutine 创建:当使用 go 关键字创建一个新的 Goroutine 时,它会被放入 P 的本地队列若本地队列已满会放到调度器的全局队列中。
- 调度器调度:Go 的调度器会将 Goroutine 分配给一个 P,P 会尝试在其本地队列中执行 Goroutine。如果本地队列已满或长时间未执行,Goroutine 会被放入全局队列。
- M 的执行:M 会从 P 的本地队列或全局队列中取出 Goroutine 并执行。当 M 空闲时,它会尝试从全局队列或其他 P 的本地队列中 “窃取” Goroutine 来执行,这种机制称为 “work stealing”。
系统信号: 调度器会周期性地向运行 Goroutine 的 M 线程发送一个系统信号(
SIGURG
)。栈扫描: 当 M 线程接收到这个信号后,会异步地暂停正在执行的 Goroutine。
栈检查: 调度器会检查这个 Goroutine 的栈,寻找一个“安全点”。所谓安全点,就是指 Goroutine 的执行状态是可中断的。
抢占: 如果找到了安全点,调度器会修改 Goroutine 的栈,将其标记为可抢占,并将其放入全局队列或本地队列。
切换: M 线程随后就会去执行其他 Goroutine。
在发生系统调用、阻塞操作时,goroutine会被挂起,切换到其他goroutine
golang GMP模型
https://fatwang1.github.io/2024/12/20/2024121900/