Files
cs-note/hzh/GolangStar/Go语言原理/gmp调度原理/gmp-summary.md
T

92 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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面试题]] — 高频面试题