golang协程调度详解之GMP模型

338 阅读1分钟

什么是GMP?

G

golang协程

M

内核线程(真正执行计算的资源)

P

逻辑处理器(队列)

调度器生命周期

  • 1 go func() 创建G
  • 2.1 放入局部队列
  • 2.2 如果局部队列已满则放入全局队列
  • 3 M1 获取G 进行计算
  • 3.1 M1 从P的本地队列中获取一个G绑定进行计算
  • 3.2 如果本地队列为空则从全局队列获取
  • 3.3 从其他的MP组合中窃取G
  • 4 调度
  • 5 执行G.func()
  • 5.1 如果G.func()发生systemCall/阻塞 (systemCall:程序从内核请求服务的一种编程方式)
  • 5.2 创建一个M 或者从休眠队列中获取一个M
  • 5.3 接管当前正在阻塞的G中的P
  • 6 销毁G
  • 7 返回

流程图

可能发生阻塞的情况

  • Channel上 send or receive
  • I/O
  • 阻塞的系统调用
  • 定时器
  • 互斥锁

多个运行队列

  • 本地运行队列
  • 全局运行队列
  • 网络轮询器

队列轮询顺序

  • 本地
  • 全局
  • 网络
  • 窃取

Channel阻塞或者I/O阻塞情况下的调度:

G被放到wait队列里面,然后M尝试运行下一个runnable的G,没有的话M解绑P进入Sleep State,阻塞完成唤醒G 标记为runnable放到P的队列中等待执行.

System Call阻塞情况下的调度:

这种情况下执行G的M也要解绑P,与G一起进入Sleep状态,如果此时有空间的M,则P与其绑定继续执行G,如果没有则创建新的M. 阻塞的G完成syscall后,G会去尝试获取一个可用的P,如果没有将G标记为Runnable,之前Sleep的M再次Sleep.

更多

公众号|杭州师薄零