脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - 曹大带我学 Go之一调度的本质

曹大带我学 Go之一调度的本质

2021-05-21 01:40码农桃花源小X Golang

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

曹大带我学 Go之一调度的本质

你好,我是小X。

曹大最近开 Go 课程了,小X 正在和曹大学 Go。

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

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

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

曹大带我学 Go之一调度的本质

生产者-消费者

生产者-消费者模型

 

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

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

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

曹大带我学 Go之一调度的本质

生产-消费过程

生产过程——三级队列

 

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

曹大带我学 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之一调度的本质

生产者动画

消费过程——调度循环

 

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

伪代码是这样的:

曹大带我学 Go之一调度的本质

调度循环

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

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

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

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

总结

 

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

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

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

原文链接:https://mp.weixin.qq.com/s/5E5V56wazp5gs9lrLvtopA

延伸 · 阅读

精彩推荐
  • Golanggolang json.Marshal 特殊html字符被转义的解决方法

    golang json.Marshal 特殊html字符被转义的解决方法

    今天小编就为大家分享一篇golang json.Marshal 特殊html字符被转义的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    李浩的life12792020-05-27
  • GolangGolang中Bit数组的实现方式

    Golang中Bit数组的实现方式

    这篇文章主要介绍了Golang中Bit数组的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    天易独尊11682021-06-09
  • Golanggolang的httpserver优雅重启方法详解

    golang的httpserver优雅重启方法详解

    这篇文章主要给大家介绍了关于golang的httpserver优雅重启的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    helight2992020-05-14
  • Golanggo日志系统logrus显示文件和行号的操作

    go日志系统logrus显示文件和行号的操作

    这篇文章主要介绍了go日志系统logrus显示文件和行号的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang 通过ssh代理连接mysql的操作

    golang 通过ssh代理连接mysql的操作

    这篇文章主要介绍了golang 通过ssh代理连接mysql的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    a165861639710342021-03-08
  • Golanggolang如何使用struct的tag属性的详细介绍

    golang如何使用struct的tag属性的详细介绍

    这篇文章主要介绍了golang如何使用struct的tag属性的详细介绍,从例子说起,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看...

    Go语言中文网11352020-05-21
  • Golanggo语言制作端口扫描器

    go语言制作端口扫描器

    本文给大家分享的是使用go语言编写的TCP端口扫描器,可以选择IP范围,扫描的端口,以及多线程,有需要的小伙伴可以参考下。 ...

    脚本之家3642020-04-25
  • GolangGolang通脉之数据类型详情

    Golang通脉之数据类型详情

    这篇文章主要介绍了Golang通脉之数据类型,在编程语言中标识符就是定义的具有某种意义的词,比如变量名、常量名、函数名等等,Go语言中标识符允许由...

    4272021-11-24