什么是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.
更多
公众号|杭州师薄零