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 的调度行为,定位高并发场景下的性能或死锁问题。

posted @ 2025-02-26 09:52  guanyubo  阅读(85)  评论(0)    收藏  举报