GMP调度模型

作为一名优秀Golang开发者来说,了解Goroutine的调度机制是必不可少的。

Goroutine的由来

我们都线程的创建,销毁以及切换,都是由操作系统来完成的,而且成本很大,而颗粒度更小的协程,创建仅需要非常小的内存,一个线程可以创建上万个协程,并且整个生命周期,都由用户自己来掌控,

大大提升了性能以及灵活性。

GMP模型的核心思想

  • 重用线程
  • 限制同时运行的线程数尽可能等于CPU的核心数目,这样可以减少切换线程带来的开支
  • 空闲偷取,以及阻塞占用等处理

GMP模型的基本概念

G: 代表的就是Goroutine
M:线程,由操作系统创建和销毁
P: Processor 处理器,用于执行Goroutine以及维护一个Goroutine队列
全局队列: 放置等待执行的Goroutine队列

GMP模型的详细过程

  • 我们通过go func()来创建一个goroutine
  • 有两个存储G的队列,一个是局部调度器P的本地队列、一个是全局G队列。新创建的G会先保存在本地队列中,如果P的本地队列已经满了就会保存在全局的队列中
  • G只能运行在M中,一个M必须持有一个P,M与P是1:1的关系,M会从P的本地队列弹出一个可执行状态的G来执行,如果P的本地队列为空,就会想其他的MP组合偷取一个可执行的G来执行
  • 一个M调度G执行的过程是一个循环机制
  • 当M执行某一个G时如果发生了syscall或者其余阻塞操作,M会阻塞,如果当前有一些G在执行,runtime会把这个线程M从P中摘除(detach),然后再创建一个新的操作系统的线程(如果有空闲的线程可用就复用空闲线程)来服务于这个P
  • 当M系统调用结束的时候,这个G会尝试获取一个空闲的P执行,并放入到这个P的本地队列,如果获取不到P,那么这个显成M会变成休眠状态,加入到空闲线程中,然后这个G会被放入全局队列中

GMP调度模型
https://www.xinyublog.com/golang/gmp/
作者
蚂蚁
发布于
2022年8月16日
许可协议