• 【GMP】当我写下go func的时候,到底发生了什么?


    背景

    原理

    我们先理解什么是G、M、P

    G∶goroutine,一个计算任务。由需要执行的代码和其上下文组成,上下文包括∶当前代码位置,栈顶、栈底地址,状态等。


    M∶ machine,系统线程,执行实体,想要在CPU上执行代码,必须有线程,与C语言中的线程相同,通过系统调用 clone 来创建。


    P:processor,虚拟处理器,M必须获得P才能执行代码,否则必须陷入休
    眠(后台监控线程除外),你也可以将其理解为一种 token,有这个 token,才有在物理 CPU核心上执行的权力。

    Go的调度流程本质上是一个生产-消费流程

    如上图所示,当我写一个go func的时候就好像我们在往队列里添加了一条数据 

    P会有一个三级队列

    第一级是runext

    第二级是local run queue

    第三级是global run queue(全局队列)

     这些队列就是用来存储我们写一次go func的时候就会生成一个G

    那这些G的生成顺序和消费顺序是怎么样的?

    一个新的G进来,它是如何存放的呢?

    G是如何被消费的呢?

    G的生成流程

    队列的存储与消费是是有优先级的

    runnext > local run queue > global run queue

    runnext最大长度为1,也就是说runext最多同时挂载一个G

    local run queue最大长度为255

    1.当runnext为空的时候

    上述代码go func表示会生成一个G,这个G是通过runtime.newproc[1]生成的

    上述表示go程序执行runtime.runqput函数把G放进runnext中

     

    2.当runext不为空的时候

    上述代码go func表示会生成一个G,这个G是通过runtime.newproc[1]生成的

     注意上述图一和图二的G

    当前正在runnext运行的G会被新生成的G抢占,并被放进local run queue中

     3.当local run queue满的时候

    因为是local run queue是有最大长度的,因此当local run queue满的时候

    Go会把local run queue的G进行打包成一个batch(batch=len(local run queue)/2 +1)

    并挂载到global run queue当中去

     

    以上就是Go中G的生成全流程

     那么接下来,我们再看看Go中是如何调度和消费G的

    G的消费流程

    我们先来认识一下Go中G的消费流程图

    P.schedtick是一个魔法数字,每当schedtick%61=0的时候,它会从全局global run queue中获取G消费

    1.当schedtick%61=0

    图中红色的G是即将要被消费的G 

    Go会通过runtime.runqget获取G

    然后执行下面👇🏻的流程

    2.当runnext有值时

    图中红色的G是即将要被消费的G 

    Go会通过runtime.runqget获取G

    然后执行下面👇🏻的流程

     

    3.当runnext为空,local run queue有G时 

    图中红色的G是即将要被消费的G 

    Go会通过runtime.runqget获取G

    然后执行下面👇🏻的流程

     4.当runnext为空,local run queue为空是,global run queue有G时

    上述图中获取3个G

    蓝色G是要即将要被消费的G

    剩余两个G会被放到local run queue中

    5.当runext,local run queue,global run queue均没有G的时候(work stealing) 

    注意上述两幅图中,箭头所指向的P 

    本文完~

    References

    1.Go程序是如何运行起来的?

    2.goroutine 生产

    3.goroutine 消费

  • 相关阅读:
    世界上第一门编程语言究竟是谁?
    归并排序的简单理解
    Go短网址项目实战---上
    Linux服务器性能监控利器-Nmon实战
    STM8的C语言编程(2)--+变量空间的分配
    【java】【项目实战】[外卖十二]【完结】项目优化(前后端分离开发)
    2023/9/13 -- C++/QT
    Go基础语法:变量和常量
    SwiftUI Bluetooth 使用
    软件测试架构师的工作日常
  • 原文地址:https://blog.csdn.net/qq_37186127/article/details/125517300