Skip to content

Latest commit

 

History

History
57 lines (53 loc) · 5.18 KB

File metadata and controls

57 lines (53 loc) · 5.18 KB


1.运行时系统相关模块

这一节只讲述调度系统。

2. 与调度相关的有下列数据有:

  • 全局M\P\G列表
  • 调度器空闲M\P列表
  • 调度器可运行的G列表
  • 调度器自由的G列表
  • 本地P可运行的G列表
  • 本地P自由的G列表

(1)全局表就不用多解释, 调度器不是一个专门的线程,而是一种资源,每个M都可能会对其进行查询,如:M的调用的时候,会首先查找调度器中的可运行队列G,然后查找本地P运行队列; 在M不够的时候,会首先调度器空闲的M列表中查找; 在程序运行过程中,使用runtime.GOMAXPROCS接口设置P上下文数量的时候,会动态的增长P的数量,这些P就是加入到调度器的空闲列表。

(2)M每次调用G的时候,必定需要一个上下文P,因为当调用的时候,可能会产生另外的G,其G的取得的步骤为, 从当前P自由G列表中取-> 从调度器自由G列表中取 -> 全局分配。当然,当该P运行完一个G后,会首先加入到P自由G列表,然后超过数量则加入到调度器自由G列表中。

3. M,P,G的对应关系

M 默认是多个, 也就是对应多个OS线程,无状态变化,唯一的变化就是是否在空闲队列中。

3.1 P的状态介绍

P可以通过runtime.GOMAXPROCS设置,一般不用设置。P具有状态:

状态机如下:

(1)M与P关联后,会从Pidle -> Prunning

(2)P变成Pdead状态,只有用户设置了P的数量减少了

3.2 G的状态介绍

状态机图:

(1)Grunning -> Gwaiting 这个状态是Golang自己的channel接收机制造成

(2)Grunning-> Gsyscall 是该协程使用了某些系统调用,如IO读取,所以直接挂起,使用的是异步IO阻塞机制

4. M,P,G运行过程:

注意:上面的全力查找注释有误,为没有则 M会挂起阻塞,然后等待被其他M唤醒

其中,全力查找可运行G的过程会通过以下几步

(1)查找本地P可运行G队列

(2)从调度器可运行G队列查找

(3)从网络IO轮询器中查找就绪G

(4)偷取别人的本地P可运行队列G

(5)再次查找调度器中的可运行G

(6)尝试从所有P中查找可运行队列G

(7)再从网络IO轮询器中查找

实在不行,就把自己和P解除联结,放置到调度器空闲队列中,并且阻塞。

其中查找到多个运行G之后的流程图如下:

5.G IO操作的运行过程

(1)当G执行IO操作后, 并且如果该G和M已经绑定,那么G阻塞(阻塞只是打个标记,并不是阻塞当前线程),IO请求由IO轮询器进行,然后M继续运行,把当前的P解除关联,M阻塞等待,当IO轮询器执行完后,然后G变成可运行状态,当其他的M找到这个绑定M的G,会把自己的上下文P解除联结,并且唤醒绑定的M,然后继续运行。

注意:当未使用G和M绑定的时候,就不会执行唤醒其他M的操作

reference : addr.