GMP 模型中的 Goroutine 状态
Go 语言 GMP 模型中的 Goroutine 状态反映了其在调度过程中的不同阶段。以下是各状态的详细说明:
1. _Grunnable(可运行状态)
- 定义:Goroutine 已准备就绪,等待被分配到操作系统线程(M)执行。
- 场景:
- 刚被创建的 Goroutine(未开始运行)。
- 从阻塞状态唤醒(如 channel 有数据可读)。
- 被抢占或分时调度器主动让出后的状态。
- 行为:
- 位于本地的 P 运行队列(或全局运行队列)中等待调度。
2. _Grunning(运行中状态)
- 定义:Goroutine 正在占用一个 M 执行用户代码。
- 关键规则:
- 一个 P 同一时刻最多有一个 Goroutine 处于此状态(因为 P 绑定到一个 M 上执行)。
- 场景:
- 正在执行用户逻辑或非阻塞的系统调用。
- 状态转换:
- 收到抢占信号(如时间片用完或手动调用 Gosched()) → 转为 _Grunnable。
- 主动阻塞(如等待 channel) → 转为 _Gwaiting。
- 执行系统调用 → 转为 _Gsyscall(若调用非阻塞)。
3. _Gsyscall(系统调用状态)
- 定义:Goroutine 正在执行阻塞式系统调用(如文件 I/O、网络请求)。
- 调度影响:
- 系统调用期间,关联的 M 会被解绑并阻塞,对应的 P 可能会被释放给其他空闲的 M(通过 handoffp 机制)。
- 状态转换:
- 系统调用完成后,若 M 能立即找回原 P → 重新进入 _Grunning。
- 若 P 已被抢占 → 转为 _Grunnable,Goroutine 加入全局运行队列等待。
4. _Gwaiting(等待/阻塞状态)
- 定义:Goroutine 因某些原因主动暂停执行(非系统调用)。
- 典型场景:
- 等待 channel 的读写操作(如 ch <- data 或 <-ch)。
- 执行 time.Sleep 或等待定时器。
- 调用 sync.Mutex.Lock() 时锁被占用。
- 触发恢复:
- 依赖外部事件(如 channel 数据到达)唤醒,标记为 _Grunnable 并加入运行队列。
5. _Gdead(终止状态)
- 定义:Goroutine 已完成任务或因异常退出。
- 行为:
- 资源会被 Go 运行时回收(或缓存复用,避免频繁分配内存)。
- 无法被调度或执行。
- 触发条件:
- Goroutine 执行完函数并正常退出。
- 程序发生 panic 且未被恢复。
附加说明:状态转换与调度策略
- 抢占机制:长时间占用 CPU 的 _Grunning Goroutine 会被调度器标记为可抢占。
- 协作式调度:通过函数调用/阻塞操作主动让出运行权,而非严格抢占(Go 1.14+ 支持基于信号的抢占优化)。
- 生命周期:
_Grunnable → _Grunning → (_Gwaiting | _Gsyscall | _Grunnable) → _Gdead.
理解这些状态有助于分析 Goroutine 的调度行为,定位高并发场景下的性能或死锁问题。
Do not communicate by sharing memory; instead, share memory by communicating.

浙公网安备 33010602011771号