GMP调度

文章目录

      • Go启动M0和G0
        • 1.场景1
      • 2.场景2 G1执行完毕
      • 3.场景3,4,5
      • 6. 场景6 唤醒正在休眠的线程
      • 7. 场景7 被唤醒的M2从全局队列获取批量G
      • 8.场景8 M2从M1偷取
      • 9.场景9 自旋线程的最大限制
      • 10. 场景10 G发送系统调用
      • 11.场景1 G发生系统调用/非阻塞

Go启动M0和G0

GMP调度_第1张图片

GMP调度_第2张图片

1.场景1

局部性,我们希望G1创建的Goroutine和G1在同一个线程,因为可能会公用到一些相同的自愿

GMP调度_第3张图片

满足局部性:G3优先加入G1的队列

2.场景2 G1执行完毕

GMP调度_第4张图片

M1上的G1执行完毕,会优先从P的本地队列的G2执行

3.场景3,4,5

P1本地队列已经满了(队列长度为4,插入G3,G4,G5,G6)

会把队列一半(G3,G4)打散然后和G7放到队列

然后G8放入队列发现队列未满就直接放入

GMP调度_第5张图片

6. 场景6 唤醒正在休眠的线程

GMP调度_第6张图片

G2唤醒M2,M2绑定P2,并且运行G0,但是P2本地没有G,M2此时为自旋线程(没有G但是不断寻找G)

7. 场景7 被唤醒的M2从全局队列获取批量G

GMP调度_第7张图片

n = min(len(GQ)/GOMAXPROCS+1,len(GQ)/2)

从全局队列到本地队列的负载均衡

8.场景8 M2从M1偷取

GMP调度_第8张图片

如果M2的本地队列没有了,全局队列也没有了,这时候会取M1的本地队列的后半部分,直接拿过来(有人说是前半部分?)

9.场景9 自旋线程的最大限制

GMP调度_第9张图片

自旋线程+执行线程<=GOMAXPROCS

10. 场景10 G发送系统调用

GMP调度_第10张图片

11.场景1 G发生系统调用/非阻塞

GMP调度_第11张图片

M2与P2解绑,但M2会记住P2,然后G8和M2进行系统调用状态,当G8和M2退出系统调用,会尝试获取P2,如果无法获取,则会获取空闲的P,如果依然没有,G8会被即为可运行状态并且加入全局队列,M2因为没有P的绑定编程休眠状态(长时间休眠会等待GC回收)

你可能感兴趣的:(Golang底层,1024程序员节,golang)