Go面试题更新 2026-08-03

在 Go 语言中,何时会发生 Goroutine 的调度?请列出并解释主要的调度时机。

考察说明

考查对 Go 运行时调度器(GMP 模型)的理解,特别是触发 goroutine 切换的时机。

回答思路

  1. 【回答框架 1】Go 的调度器基于 GMP 模型,其中 M 代表系统线程,P 代表逻辑处理器,G 代表 goroutine。调度器负责在适当的时候将 G 从 P 的运行队列中取出并绑定到 M 上执行。
  2. 【回答框架 2】主要的调度时机包括主动调度:当 goroutine 执行阻塞操作(如 channel 发送/接收、锁等待、time.Sleep、系统调用)时,会主动让出处理器,使得其他 goroutine 获得执行机会。
  3. 【回答框架 3】被动调度:当 goroutine 发生抢占时,例如运行时间超过 10ms 或遇到抢占点(如函数调用),编译器会插入抢占检查,调度器会暂停当前 goroutine,切换为其他任务。
  4. 【回答框架 4】另外,在 GC 或 垃圾回收期间,会进行 stop the world 调度,等待所有 goroutine 达到安全点,再执行回收。
  5. 【关键点 1】调度时机分为主动调度(阻塞操作让出)和被动调度(抢占和 GC STW)。
  6. 【关键点 2】阻塞操作包括 channel、锁、time.Sleep、系统调用等。
  7. 【关键点 3】抢占主要通过 sysmon 检测超时并插入抢占。
  8. 【关键点 4】GC 也会触发 goroutine 暂停和恢复。
  9. 【易错点 1】不要误以为所有阻塞操作都会立即触发调度,例如无缓冲 channel 的发送和接收确实会阻塞并让出,但有缓冲 channel 在缓冲区未满时可能不会阻塞。
  10. 【易错点 2】避免混淆用户态调度与内核线程调度,goroutine 切换不会必然导致系统线程的上下文切换。
  11. 【易错点 3】不要遗漏抢占机制的存在,过去 Go 版本仅依赖协作式调度,但现代 Go 已有非协作式抢占。