今天学习了之前买的课程,今天主要是学习了一下goroutine的调度相关的事情。有了一个全新的认识
GMP调度分解
在go中,经过了多代的更新,才使用了现在的GMP调度,这里我们需要知道的是GMP到底都代表的什么东西
G
首先我们就来说一下这个G,在go语言中,每一个任务我们都封装成一个G,可以把G理解成一个任务。
M
M就是处理器,也就是是实体的线程,有了实体线程才能进行处理
P
P就是这个协程处理的时候需要的资源,可以说P相当于一个token,有了这个token才能进行相关的处理。也就是说有了P, M才能进行处理。
##GMP调度
对于goroutine的调度,我们可以想像成一个生产消费的模型。
在详细的学习生产消费的时候,我们首先来认识一下,对于协程调度的几个东西。
这是一个完成的内部图片,我们首先认识一下里面的结构,其中GMP我们都认识了,现在主要是认识一下其他的东西,特别是三个队列。
我们可以清楚的看到,有三个队列:runnext、本地队列、全局队列
后面我们会详细的说明这个几个队列的详细细节。
首先第一个runnext就只能放下一个Goruntine
第二个本地队列是用的数组实现的。为什么?主要依据的是局部性原理,最后调用的程序,可能是最进行调用的,所以我们使用的是数组实现。这里的数组大小是256.
第三那个全局的队列,是使用的是链表的数据结构实现的。
生产
有了生产消费的模型,现在我们来看一下生产端是怎么来进行的。
在这里,主要需要了解的事情就是runqput这里是怎么进行运行的,也就是goruntine是怎么选择队列进行存储的。
首先创建出来的G,首先会到runnext,然后如果说runnext上有G,我们就会将老的G进行踢出,然后将老的G放入到本地队列中。如果本地队列放满了,这个时候我们会将这个G,然后加上本地队列的一半生成一个batch,转换成链表加入到全局队列中。
这里我们大概的讲解了一下生产的逻辑,然后我们下面来看一下消费的逻辑。
消费
上面的就是消费端的结构图,其实消费的逻辑,就是在这个四个里面一直进行循环,但是对于不同的队列中我们还是有不同的调度。
在这个循环里面有一个魔法数字,61。下面我们就进行详细的讲解。
进入这个循环过后,我们首先对循环次数进行61取模,当为0的时候,我们就会取全局队列的第一个G进行执行。当然如果不是,我们回去runnext中取,如果有就执行,如果没有我们就会在本地队列中进行查找,然后取出进行执行,当然我们也会遇见本地队列也没有的情况,这个时候我们会取全局队列中取,首先拿出一半,然后取一个取执行,其他的放入本地队列。在这里如果都没有的时候,我们的调度也不会结束,而是取其他的处理器中取取。
总结
GMP的调度过程,看代码确实有点打老壳,但是有了这个图后,我觉得更加的好理解。
最后感谢大家的观看,希望大家多多支持,给我点点赞谢谢。