深入理解 Go | 调度:GMP 模型(第三部分)



以下基于 Go 1.14

Go 程序中,在下面几种情况下都有可能触发调度(即调用 runtime.schedule()):

  • 创建一个新的线程时
  • goroutine 执行结束的时候
  • 主动挂起
  • 协作式调度
  • 基于函数调用的抢占式调度
  • 基于信号的抢占式调度(Go 1.14 新特性)
  • 系统调用

前面已经提到过前面两种,下面看下其他几种情况的行为方式。

主动挂起

当有诸如 time.Sleep()、锁、channel 之类的操作时,就会主动挂起 goroutine。而 goroutine 的主动挂起和唤醒分别是通过 runtime.gopark()runtime.goready() 实现的:



系统调用

不是所有的系统调用都会触发调度,只有那些需要运行时参与的系统调用(syscall.Syscall())才有可能触发调度:



协作式调度

协作式调度指的是 goroutine 主动让出处理器,从而允许其他 goroutine 运行:



抢占式调度

Go 语言的抢占式调度是在分段栈的机制上实现的。编译器会在分段栈上插入函数,这样,所有的 goroutine 在进行函数调用的时候都有机会进入运行时检查是否需要抢占。

但是,这种机制对于诸如轮询计算这种没有函数调用的 goroutine 来说,是无法抢占成功的。因此,Go 1.14 版本引入了基于信号的抢占式调度。



请言小午吃个甜筒~~