[每周一更]-(第51期):Go的调度器GMP

在这里插入图片描述

参考文献

  • https://learnku.com/articles/41728
  • http://go.cyub.vip/gmp/gmp-model.html#g-m-p
  • https://blog.csdn.net/ByteDanceTech/article/details/129292683
  • https://www.ququ123.top/2022/04/golang_gmp_principle/

什么是GMP?

GMP模型是Go语言并发模型的核心概念,用于管理和调度Goroutine的执行。它包含三个主要组件:Goroutine(协程)、M(机器)和P(处理器)。

Go 为了自身 goroutine 执行和调度的效率,自身在 runtime 中实现了一套 goroutine 的调度器

G-M-P分别代表:
  • G - Goroutine,Go协程,是参与调度与执行的最小单位
  • M - Machine,指的是系统级线程,每个M绑定到一个操作系统线程上。M负责调度和管理Goroutine,它会将Goroutine分配给可用的P进行执行。一个Go程序通常会有多个M,用于实现并发执行。
  • P - Processor,指的是逻辑处理器,P关联了的本地可运行G的队列(也称为LRQ),最多可存放256个G。P负责管理和执行Goroutine,它与M是一对一的关系。P维护了一个Goroutine队列(runqueue),它从队列中获取Goroutine并分配给M执行。
    在这里插入图片描述
G-M-P的数量
  • G 的数量:
    理论上没有数量上限限制的。查看当前G的数量可以使用runtime. NumGoroutine()

  • P 的数量:
    由启动时环境变量 $GOMAXPROCS 或者是由runtime.GOMAXPROCS() 决定。这意味着在程序执行的任意时刻都只有 $GOMAXPROCS 个 goroutine 在同时运行。

  • M 的数量:
    go 语言本身的限制:go 程序启动时,会设置 M 的最大数量,默认 10000. 但是内核很难支持这么多的线程数,所以这个限制可以忽略。 runtime/debug 中的 SetMaxThreads 函数,设置 M 的最大数量 一个 M 阻塞了,会创建新的 M。M 与 P 的数量没有绝对关系,一个 M 阻塞,P 就会去创建或者切换另一个 M,所以,即使 P 的默认数量是 1,也有可能会创建很多个 M 出来。

GMP的工作模式

  • 首先创建一个新的 goroutine
  • 如果本地的局部队列中有足够的空间可以存放,则放入局部队列中;如果局部队列满,则放入一个全局队列(所有的 M 都可以从全局队列中拉取 G 来执行)
  • 所有的 G 都必须在 M 上才可以被执行,M 和 P 存在一一绑定的关系,如果 M 绑定的 P 中存在可以被执行的 G,则从 P 中拉取 G 来执行;如果 P 中为空,没有可执行的 G,则 M 从全局队列中拉取;如果全局队列也为空,则从其他的 P 中拉取 G
  • 为 G 的运行分配必要的资源,等待 CPU 的调度
  • 分配到 CPU,执行 func(){}
    在这里插入图片描述
调度过程中阻塞

GMP模型的阻塞可能发生在下面几种情况:

  • I/O,select
  • block on syscall
  • channel
  • 等待锁
  • runtime.Gosched()
用户态阻塞

当goroutine因为channel操作或者network I/O而阻塞时(实际上golang已经用netpoller实现了goroutine网络I/O阻塞不会导致M被阻塞,仅阻塞G),对应的G会被放置到某个wait队列(如channel的waitq),该G的状态由_Gruning变为_Gwaitting,而M会跳过该G尝试获取并执行下一个G,如果此时没有runnable的G供M运行,那么M将解绑P,并进入sleep状态;当阻塞的G被另一端的G2唤醒时(比如channel的可读/写通知),G被标记为runnable,尝试加入G2所在P的runnext,然后再是P的Local队列和Global队列。

系统调用阻塞

当G被阻塞在某个系统调用上时,此时G会阻塞在_Gsyscall状态,M也处于 block on syscall 状态,此时的M可被抢占调度:执行该G的M会与P解绑,而P则尝试与其它idle的M绑定,继续执行其它G。如果没有其它idle的M,但P的Local队列中仍然有G需要执行,则创建一个新的M;当系统调用完成后,G会重新尝试获取一个idle的P进入它的Local队列恢复执行,如果没有idle的P,G会被标记为runnable加入到Global队列。

一种形象的栗子

地鼠(Gopher)的工作任务是:工地上有若干砖头,地鼠借助小车把砖头运送到火种上去烧制。M 就可以看作图中的地鼠,P 就是小车,G 就是小车里装的砖。
弄清楚了它们三者的关系,下面我们就开始重点聊地鼠是如何在搬运砖块的。

  • Processor(P):
    根据用户设置的 GoMAXPROCS 值来创建一批小车§。
  • Goroutine(G):
    通过 Go 关键字就是用来创建一个 Goroutine,也就相当于制造一块砖(G),然后将这块砖(G)放入当前这辆小车§中。
  • Machine (M):
    地鼠(M)不能通过外部创建出来,只能砖(G)太多了,地鼠(M)又太少了,实在忙不过来,刚好还有空闲的小车§没有使用,那就从别处再借些地鼠(M)过来直到把小车§用完为止。
    这里有一个地鼠(M)不够用,从别处借地鼠(M)的过程,这个过程就是创建一个内核线程(M)。
    需要注意的是:地鼠(M) 如果没有小车§是没办法运砖的,小车§的数量决定了能够干活的地鼠(M)数量,在 Go 程序里面对应的是活动线程数;
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/287204.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ARM CCA机密计算架构软件栈之软件组件介绍

在本节中,您将了解Arm CCA的软件组件,包括Realm World和Monitor Root World。以下图表展示了Arm CCA系统中的软件组件: 在这个图表中,世界之间的边界显示为粗虚线。由较高权限的软件强制执行的较低权限软件组件之间的边界显示为细虚线。例如,非安全EL2处的虚拟机监视器强制…

QT上位机开发(会员管理软件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们学习了ini文件的解析办法,通过QSettings类就可以很轻松地访问ini文件里面的数据。除了ini文件之外,另外一种经常出…

什么是数据销毁,为什么数据销毁很重要

当大多数人听到“数据破坏”时,他们的脸上都会表现出恐惧的表情。世界上大多数人最不想要的就是销毁他们计算机或移动设备上的数据。但现实情况是,无论您是大型、中型还是小型企业的所有者,总有一天您需要移除或更换旧媒体,并且您…

SpringBoot学习(二)-SpringBoot Web 开发

注:此为笔者学习狂神说SpringBoot的笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!! SpringBoot Web 开发 1、静态资源 1)创建项目 2)做项目都先测试一…

[每周一更]-(第52期):Go的函数式编程

参考地址 https://hedzr.com/golang/fp/golang-functional-programming-in-brief/https://silverrainz.me/blog/funtional-programming-in-go-generics.htmlhttps://zhuanlan.zhihu.com/p/436468481 函数式编程(Functional Programming / FP)作为一种编…

解决实用编程题目:单词拆分和分割等和子集--动态规划方式深度呈现

139. 单词拆分 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s "lee…

OpenCV图像处理——C++实现亚像素尺寸标定板边缘轮廓提取

前言 标定模板(Calibration Target)在机器视觉、图像测量、摄影测量以及三维重建等应用中起着重要的作用。它被用于校正相机的畸变,确定物理尺寸和像素之间的换算关系,并建立相机成像的几何模型。通过使用相机拍摄带有固定间距图…

JavaScript中的数据缓存与内存泄露:解密前端性能优化与代码健康

​🌈个人主页:前端青山 🔥系列专栏:JavaScript篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-数据缓存与内存泄露 目录 说说你对事件循环的理解 一、是什么 二、宏…

Linux操作系统基础(7):Linux的文件路径

1. Linux文件路径的介绍 在Linux系统中,文件路径是用来定位文件或目录在文件系统中位置的一种表示方法,它能够帮助用户快速、准确地定位文件或目录,并进行相应的操作。 文件路径可以分为 绝对路径 和 相对路径 两种类型: 绝对路…

H266/VVC熵编码技术概述

熵编码 熵编码: 是指按信息熵原理进行的无损编码方式,无损熵编码也是有损视频编码中的一个关键模块,它处于视频压缩系统的最末端。熵编码把一列系用来表示视频序列的元素符号转变为一个用来传输或存储的压缩码流,输入的符号可能包…

提高开发效率的必备!超实用的VSCode插件推荐

前言 作为一个前端程序猿,我经常使用 VSCode 代码编辑器,但是每个开发者都有自己独特的工作风格和偏好。为了满足不同开发者的需求,VSCode 提供了丰富的插件生态系统。在本文中,我将为大家推荐一些强大的 VSCode 插件,…

Linux学习之系统编程3(进程及wait函数)

写在前面: 我的Linux的学习之路非常坎坷。第一次学习Linux是在大一下的开学没多久,结果因为不会安装VMware就无疾而终了,可以说是没开始就失败了。第二次学习Linux是在大一下快放暑假(那个时候刚刚过完考试周)&#xf…

SpringFrameWork

SpringFrameWork简介 介绍springFrameWork框架 Spring Framework是一个为企业级应用程序开发提供全面基础设施支持的开源框架,通过集成IoC、DI和AOP等技术,使得应用程序的开发更加灵活、可维护和可扩展。Spring MVC、SpringBoot、Spring Cloud、Spring D…

java实现大文件分片上传

背景: 公司后台管理系统有个需求,需要上传体积比较大的文件:500M-1024M;此时普通的文件上传显然有些吃力了,加上我司服务器配置本就不高,带宽也不大,所以必须考虑多线程异步上传来提…

数据结构与算法python版本之线性结构之队列Quene

什么是队列? 队列是一种有次序的数据集合,其特征是:新数据项的添加总发生在一端(通常称为“尾rear”端),而现存数据项的移除总发生在另一端(通常称为“首front”端);当数…

缓存数据一致性策略如何分类?

一、概述 数据库与缓存数据一致性问题,一直以来都是大家比较关注的问题。针对一致性的解决方案也是非常多,以下主要针对方案的梳理与分类: 数据库数据与缓存数据一致性的方案,可以从不同的角度来分类,比如&#xff1…

稳定币记录

稳定币: 稳定币(Stablecoin)是一种加密货币,其设计目的是维持相对稳定的价值,通常与某种法定货币(如美元、欧元)或其他资产(如黄金)挂钩。稳定币通过将加密货币与相应的…

Flink-【时间语义、窗口、水位线】

1. 时间语义 1.1 事件时间:数据产生的事件(机器时间); 1.2 处理时间:数据处理的时间(系统时间)。 🌰:可乐 可乐的生产日期 事件时间(可乐产生的时间&…

计算机毕业设计 SpringBoot的停车场管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

逻辑回归算法到底能做什么

逻辑回归(Logistic Regression)是一种广义的线性回归分析模型,常用于数据挖掘、疾病自动诊断、经济预测等领域。它根据给定的自变量数据集来估计事件的发生概率。变量的范围在0和1之间,通常用于二分类问题,最终输出的预…