92 lines
3.5 KiB
Markdown
92 lines
3.5 KiB
Markdown
---
|
||
tags: [go, golang, go-principle, gmp-scheduler, summary, cheat-sheet]
|
||
create time: 2026-06-07 16:00
|
||
---
|
||
|
||
# GMP 调度原理 — 知识卡片
|
||
|
||
## 概述
|
||
|
||
本节汇总 GMP 调度模型的全景流程与核心要点,适合作为复习回顾的速查卡片。涵盖 §6:完整生命周期流程图和关键概念总结。
|
||
|
||
## 正文
|
||
|
||
### 6.1 GMP 全景流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
subgraph Create["创建 goroutine"]
|
||
NewProc["runtime.newproc<br/>systemstack → newproc1<br/>runqput → LRQ/GRQ"]
|
||
end
|
||
|
||
subgraph Schedule["调度循环"]
|
||
ScheduleFn["schedule → findRunnable"]
|
||
FindR["findRunnable: LRQ → GRQ → netpoll → steal"]
|
||
Execute["execute → gogo(g)"]
|
||
end
|
||
|
||
subgraph Yield["让出执行权"]
|
||
End["goexit1 → goexit0<br/>status=Gdead, gfput"]
|
||
Gosched["Gosched → gosched_m<br/>status=Grunnable, globrunqput"]
|
||
Park["gopark → park_m<br/>status=Gwaiting, 上层管理"]
|
||
end
|
||
|
||
subgraph Preempt["抢占 sysmon"]
|
||
Sysmon["sysmon 线程"]
|
||
Retake["retake: syscall + timeout"]
|
||
Collab["协作式: stackPreempt"]
|
||
Signal["非协作式: sigPreempt"]
|
||
end
|
||
|
||
subgraph Recover["恢复执行"]
|
||
Ready["goready → ready<br/>status=Grunnable, runqput"]
|
||
end
|
||
|
||
Create --> Schedule
|
||
Schedule --> Yield
|
||
Yield --> Recover
|
||
Recover --> Schedule
|
||
Sysmon --> Preempt
|
||
Preempt --> Yield
|
||
style Create fill:#e3f2fd
|
||
style Schedule fill:#e8f5e9
|
||
style Yield fill:#fff3e0
|
||
style Preempt fill:#ffebee
|
||
style Recover fill:#e8f5e9
|
||
```
|
||
|
||
### 6.2 核心要点速查
|
||
|
||
| 维度 | 要点 |
|
||
|------|------|
|
||
| **角色分工** | G = 任务(goroutine),M = 工人(OS 线程),P = 主管(逻辑处理器) |
|
||
| **队列优先级** | LRQ(无锁 CAS)> GRQ(加锁)> netpoll(IO)> steal(工作窃取) |
|
||
| **防饥饿** | 每 61 次调度强制检查一次 GRQ |
|
||
| **LRQ 容量** | 256 个 G;满时触发 `runqputslow` 批量迁移至 GRQ |
|
||
| **runnext** | VIP 位置,新创建的 G 优先放入,下次调度直接执行 |
|
||
| **协程状态机** | `_Gidle → _Grunnable → _Grunning → { _Gdead / _Gwaiting / _Gsyscall }` |
|
||
| **让渡方式** | 结束→回收到 `gfree`;`Gosched`→入 GRQ;`gopark`→`_Gwaiting` 由上层保管 |
|
||
| **唤醒机制** | `goready → ready`:改状态→`runqput`→`wakep()` |
|
||
| **系统调用抢占** | `reentersyscall` 解绑 P/M;exitsyscall 快速路径复用 oldP / 慢速路径重新分配 |
|
||
| **协作式抢占** | 设置 `stackPreempt`,在函数调用/栈检查时响应 |
|
||
| **非协作式抢占** | Go ≥ 1.14,通过 POSIX 信号注入 `asyncPreempt`,绕过函数调用依赖 |
|
||
| **sysmon 三板斧** | netpoll(IO 轮询)→ retake(抢占检查)→ GC 触发 |
|
||
|
||
### 6.3 关键数据记忆点
|
||
|
||
| 数字 | 含义 |
|
||
|------|------|
|
||
| **256** | LRQ 最大容量 |
|
||
| **61** | 每次 GRQ 强制检查间隔(schedtick) |
|
||
| **10ms** | syscall 超时阈值、运行抢占阈值(`forcePreemptNS`) |
|
||
| **4** | work-stealing 最大试探轮数 |
|
||
| **128** | netpoll epoll_wait 单次最多返回事件数 |
|
||
|
||
## 关联笔记
|
||
|
||
- [[hzh/GolangStar/Go语言原理/gmp调度原理/gmp-overview]] — GMP 概览
|
||
- [[hzh/GolangStar/Go语言原理/gmp调度原理/gmp-datastructures]] — G/M/P/Schedt 数据结构
|
||
- [[hzh/GolangStar/Go语言原理/gmp调度原理/gmp-lifecycle]] — Goroutine 生命周期
|
||
- [[hzh/GolangStar/Go语言原理/gmp调度原理/gmp-preemption]] — 抢占式调度机制
|
||
- [[hzh/GolangStar/Go面试题库/GMP面试题]] — 高频面试题
|