Go(1)——调度的本质

简介: Go(1)——调度的本质

这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go。

上周课程已经开始了,曹大直播了第一期,干货满满,大呼过瘾。第一课之后,陆续又加进来了一些同学。

首先抛出本文的结论:Go 调度的本质是一个生产-消费流程。

 生产者-消费者

生产者-消费者模型

我们平时用 Go 最爽的一点莫过于用一句 go func(){}() 就启动了一个 goroutine 来并发地执行任务。这比用 C/C++ 启动一个线程并发地去执行任务方便太多。这句代码实际上就生产出了一个 goroutine,并进入可运行队列,等待和 m 来找它从而可以得到运行。


熟悉 GMP 模型的朋友都知道,goroutine 最终在 m 上得以执行,因为操作系统感知不到 goroutine,它只能感知线程,并且线程可以看成是 m。


所以,m 拿到 goroutine 并运行它的过程就是一个消费过程。

   生产-消费过程

生产过程——三级队列

生产出的 goroutine 需要找一个地方存放,这个地方就是可运行队列。在 Go 程序中,可运行队列是分级的,分为三级:

                                                                                                三级可运行队列

runnext 实际上只能指向一个 goroutine,所以它是一个特殊的队列。


那把 goroutine 放到哪个可运行队列呢?看情况。


首先,如果 runnext 为空,那么 goroutine 就会顺利地放入 runnext,接下来,它会以最高优先级得到运行,即优先被消费。


如果 runnext 不为空,那就先负责把 runnext 上的 old goroutine 踢走,再把 new goroutine 放上来。具体踢到哪里呢?又得分情况。


local queue 是一个大小为 256 的数组,实际上用 head 和 tail 指针把它当成一个环形数组在使用。如果 local queue 不满,则将 runnext 放入 local queue;否则,P 的本地队列上的 goroutine 太多了,说明当前 P 的任务太重了,需要减负,因此需要得到其他 P 协助。从而,将 runnext 以及当前 P 的一半 goroutine 一起打包丢到 global queue 里去。


当然,这部分课程里有非常生动的动画,这里贴一个截图大家感受一下:

生产者动画

消费过程——调度循环


之前的文章里也讲到过调度循环是咋回事,它实际上就是 Go 程序在启动的时候,会创建和 CPU 核心数相等个数的 P,会创建初始的 m,称为 m0。这个 m0 会启动一个调度循环:不断地找 g,执行,再找 g……

伪代码是这样的:

调度循环

随着程序的运行,m 更多地被创建出来,因此会有更多的调度循环在执行。


那边生产者在不断地生产 g,这边 m 的调度循环不断地在消费 g,整个过程就 run 起来了。


找 g 的过程中当然也是从上面的三级队列里找:


先看 runnext,再看 local queue,再看 global queue。当然,如果实在找不到,就去其他 p 去偷。

总结

今天的文章只用记住一个观点:Go 调度的本质是一个生产-消费流程。这个观点非常新颖,之前我没有从哪篇文章看到过,这是曹大自己的感悟。


读者即使之前没见过类似的说法,但是一旦听曹大讲出来,就马上感觉醍醐灌顶。


这种熟悉加意外的效果其实就是你成长的时机。


好了,这就是今天全部的内容了~ 我是小X,我们下期再见~

相关文章
|
6月前
|
Go 调度 开发者
CSP模型与Goroutine调度的协同作用:构建高效并发的Go语言世界
【2月更文挑战第17天】在Go语言的并发编程中,CSP模型与Goroutine调度机制相互协同,共同构建了高效并发的运行环境。CSP模型通过通道(channel)实现了进程间的通信与同步,而Goroutine调度机制则确保了并发任务的合理调度与执行。本文将深入探讨CSP模型与Goroutine调度的协同作用,分析它们如何共同促进Go语言并发性能的提升。
|
Go 调度
go基于信号的抢占式调度
go的调度器默认为抢占式调度。
205 0
|
缓存 Go 调度
Go并发调度进阶-循环调度,不是你理解的死循环
Go并发调度进阶-循环调度,不是你理解的死循环
|
监控 Java Go
Go并发调度进阶-GMP初始化,最难啃的有时候耐心看完还是很简单的
Go并发调度进阶-GMP初始化,最难啃的有时候耐心看完还是很简单的
|
存储 缓存 算法
Go并发调度进阶-GMP和调度器的主要结构,只有接触到底层你才更有底气
Go并发调度进阶-GMP和调度器的主要结构,只有接触到底层你才更有底气
Go并发调度-调度器设计理念从何而来?为何如此高效?
Go并发调度-调度器设计理念从何而来?为何如此高效?
|
缓存 Java Go
Go的GMP调度模型,看这篇就足够了
Go的GMP调度模型,看这篇就足够了
|
安全 Go 调度
go一个协程安全协程调度的问题
go一个协程安全协程调度的问题
117 0
go一个协程安全协程调度的问题
|
Java Go 调度
go的GMP调度
快速学习go的GMP调度
|
存储 Java Go
Go基础:goroutine使用、调度、runtime包
Go基础:goroutine使用、调度、runtime包
245 0
Go基础:goroutine使用、调度、runtime包