【golang】调度系统之整体介绍

调度系列
调度系列之goroutine
调度系列之m
调度系列之p
调度系列之sysmon

前面几篇对调度体系的G、M、P、sysmon分别进行了介绍。拆分的介绍有助于聚焦单一的角色,比较快地建立认识,同时也能更深入细节,但是不足以建立全局的认知。本篇在前面几篇的基础上,进行汇总的介绍。介绍的方式为选取runtime的几个阶段,介绍调度体系在对应阶段的状态,以及阶段之间的演进。

阶段1

【golang】调度系统之整体介绍_第1张图片

在此阶段,runtime已经初始化,系统中存在4个p。系统的负载很低,目前只有3个goroutine,p0、p1、p2被M占据并运行goroutine,p3处于idle状态。

阶段2

【golang】调度系统之整体介绍_第2张图片

此时系统的负载仍然很低,没有新的goroutine创建。

  • p2上运行的goroutine结束后,对应的M进入schedule中,尝试从本地就绪队列、全局就绪队列、netpoll或者runnable的goroutine。
  • 获取不到后M进入spinning状态,尝试从其他的P中获取runnable的goroutine(steal work)。steal work会尝试4次,每次随机选择一个P进行。
  • M的spinning是一个非常短暂存在的状态。

阶段3

【golang】调度系统之整体介绍_第3张图片

在阶段2中,占据p2的M处于spinning状态。但此时的系统中显然没有goroutine供其运行。处于spinning状态的M在获取不到goroutine后会释放占据的p,将其置为idle状态,然后将自己挂起,置于midle队列的头部。

阶段4

【golang】调度系统之整体介绍_第4张图片

此时系统的负载上升,我们的生产应用绝大部分时间都处于该状态。

  • 每个p的本地就绪队列以及全局的就绪队列中都有goroutine等待调度。p1、p2、p3处于running状态。
  • p0上运行的goroutine在执行系统调用,处于syscall状态,此时M占据p进行系统调用。
  • 另外还有M没有占据p进行系统调用,这可能是被sysmon检测到执行时间过久进行的解绑,也有可能是在系统调用之初主动handoffp。
  • 也有一些goroutine处于阻塞队列中。

阶段5

【golang】调度系统之整体介绍_第5张图片
  • 此时p0由syscall转变为running状态;
    • 可能是因为系统调用结束,M主动将p0状态由syscall -> running;
    • 也可能是p0处于syscall状态的时间过长(超过10ms),被sysmon进行解绑。
  • 处于syscall状态的g对应的M在系统系统调用结束后会重新尝试获取P,如果获取不到,则g挂载在全局就绪队列中,M挂载到midle中。
  • 另外和goroutine绑定的M在goroutine被调度时也会挂载到midle中。

以上为调度系统的整体的介绍。

你可能感兴趣的:(golang,runtime,调度,GMP)