阅读本文需要有一定的基础:

  • 线程与协程之间的关系
  • 线程模型

G & M & P

  • Goroutine,协程
  • Machine,系统线程,OS调度的最小单位
  • Processor,局部调度器,或者叫做「逻辑处理器」,负责调度G,并将之映射到M上

所谓的GMP模型,就是Go自己实现的一套并发调度的模型,自己创建协程,自己调度协程,自己将协程映射到线程上。整体来看,就像线程的多对多模型:
image.pngimage.png
所谓的G就对应用户线程,M就是内核线程,而P就是它们之间的交点,负责管理映射关系、调度协程(有点像LWP的作用)。如果要具象化到GMP模型的示意图的话,借用一下别人的图:
image.png
从这张图可以看出来,P之所以叫做逻辑处理器,是对于G而言的,G的视角就是,自己放在P上跑。所以,真正的并行度是由CPU核数、M与P决定的。

整体流程与逻辑

怎么跑起来

讨论GMP之间的逻辑

  • M需要绑定P,否则就会去休眠
  • 当G在执行阻塞系统调用的时候,M与P会解绑,P会带着自己的G们去找下一个M
    • 关于阻塞,主要分为用户态以及系统态的阻塞
    • 用户态,比如IO、channel等原因导致的,就会将G放到waiting队列中,M去执行下一个G
    • 系统态,则会解绑P
  • 在创建G的时候,会尝试唤醒其他的MP组合

    G的调度

  • 当创建G的时候,如果本地队列满了,则会放到全局队列中

  • M会尝试从全局队列中选取一部分加入自己的本地队列
  • M在全局为空的时候,可能会去偷其他MP组合的本地内容

image.png
M给我的感觉有点像,被Go程序所占用的线程,Go也会像线程池那样对其进行管理,在没有G的时候,会进入自旋状态

全局调度器schedt

P可以理解为一个M的局部调度器,而schedt则会维护M的全局idle队列、P的全局idle队列、G的全局队列(就绪)以及锁。在进行全局调度,比如P与M解绑回归全局idle队列时,就需要它负责。

Links

文章基本都说的比较详细,不过描述上略有侧重,也许能更好地帮助理解