Golang调度器

G:goroutine

P:逻辑处理器

M:真正执行计算的资源

每个goroutine都有一个状态,Scheduler根据状态知道要运行哪个goroutine

  • 可运行(Running)

  • 正在运行(Runnable)

  • 已经阻塞(Blocked)

M:N 有一个全局运行队列(Global Run Queue) , 某些操作会将新的Goroutines放入运行队列。

但是那些阻塞的Goroutines会在哪里呢?

可能阻塞的情况:

  • Channel上 send or receive

  • I/O

  • 阻塞的系统调用

  • 定时器

  • 互斥锁

基本原理:阻塞的goroutines不应该阻塞内核底层线程

多个运行队列:

  • 本地全局运行队列

  • 全局运行队列

  • 网络轮询器

队列轮询顺序:

  1. 本地

  2. 全局

  3. 网络

  4. 工作偷窃 

Scheduler功能:

  • 并行处理(使用多线程)

  • 处理阻塞系统调用和网络I/O

  • 处理用户级别(like Channel)阻塞调用

  • 可伸缩扩展

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.

猜你喜欢

转载自blog.csdn.net/coffiasd/article/details/115524955