go并发模型GPM

2023-11-18

线程模型的三种实现方式:

用户级线程:M:1对应关系,多个用户态线程对应着一个内核线程,用户态线程的创建、终止、切换、同步等线程工作必须由自身来完成。
内核级线程:1:1对应关系,直接调用操作系统的内核线程,所有线程的创建、终止、切换、同步等操作都由内核线程来完成。
两级线程:M:N对应关系,这种线程模型会先创建多个内核级线程,然后用自身的用户级线程去对应创建的多个内核级线程,自身的用户级线程需要本身程序去调度,内核级的线程交给操作系统内核去调度。

go实现了特殊的两级线程模型,用户调度器实现用户线程到KSE(kernel scheduling entity)的调度,内核线程实现KSE到cpu的调度。
在这里插入图片描述

go线程模型GPM

在这里插入图片描述
G: goroutine, 类似于操作系统中的进程控制块,主要包含以下信息:

  • 函数指令及参数
  • 栈信息
  • 线程上下文信息(goroutine切换时,用于保存 g 的上下文,例如,变量、相关信息等)
  • 现场保护和现场恢复需要的寄存器(SP、IP)
  • 当前执行的m
  • 被阻塞的时间

P: processor, 逻辑处理器,是一个抽象的概念,并不是物理CPU。保存一个队列G, P/M需要进行绑定形成一个执行单元。P决定了可以同时并发的任务数量。可以通过runtime.GOMAXPROCS进行指定(最大256),Go1.5之后GOMAXPROCS被默认设置可用的核数。主要包含以下信息:

  • 状态(空闲,运行中)
  • 关联的m
  • 可运行的goroutine队列 (也称本地队列)
  • 下一个g

M: machine, 操作器,是一个线程,用于将一个 G 搬到线程上执行。所有的M是有线程栈的

  • g0 *g : 所有调用栈的Goroutine, m专属的线程栈,(普通的goroutine是在heap上分配的可增长的stack,因为 goroutine 可以越开越多)
  • curg *g : 当前运行在m上的g
  • 状态(空闲,运行中)
  • 关联的p
  • SP、PC寄存器用于现场保护和现场恢复

LRQ: 本地队列,每个p独有的队列,本地队列是lock-free,没有数据竞争问题,无需加锁,可以提升处理速度。
GRQ:全局队列,所有m共享的全局队列。可以保证p之间任务的平衡。由于有数据竞争问题,需要加锁,处理速度低于本地队列。

go调度器调度过程

首先创建一个g, 保存到p本地队列或者全局队列。然后p去唤醒一个m, p继续执行自己的执行序,m去找是否有空闲的p,找到后将p上面的一个g搬运到本身,最后执行一个调度循环(调用g对象,执行-清理线程-继续寻找新的g对象)

线程清理

Goroutine被调度执行必须保证P/M进行绑定,所以线程清理只需要将P释放(解除绑定)就可以实现线程的清理。什么时候P会释放,保证其它G可以被执行。P被释放主要有两种情况。

  • 主动释放:最典型的例子是,当执行G任务时有系统调用,当发生系统调用时M会处于阻塞状态。调度器会设置一个超时时间,当超时时会将P释放。
  • 被动释放:如果发生系统调用,有一个专门监控程序,进行扫描当前处于阻塞的P/M组合。当超过系统程序设置的超时时间,会自动将P资源抢走。去执行队列的其它G任务。

上下文切换

简单理解为当时的环境即可,环境可以包括当时程序状态以及变量状态。

对于代码中某个值说,上下文是指这个值所在的局部(全局)作用域对象。相对于进程而言,上下文就是进程执行时的环境,具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存(堆栈)信息等。
Go调度器根据事件进行上下文切换。

Go调度器根据事件进行上下文切换。

  • go关键字,创建goroutine
  • gc垃圾回收,gc也是goroutine,所以需要时间片
  • system call系统调用,block当前G
  • sync同步,block当前G

异步调用

Linux可以通过epoll实现网络调用,统称网络轮询器N(Net Poller)。

  1. G1在M上运行,P的LRQ有其他3个G,N空闲;
  2. G1进行网络IO,因此被移动到N,M继续从LRQ取其他的G执行。比如G2就被上下文切换到M上;
  3. G1结束网络请求,收到响应,G1被移回LRQ,等待切换到M执行。

同步调用(如文件I/O)

  1. G1在M上运行,P的LRQ有其他3个G,G1进行同步调用阻塞M1;
  2. 调度器接入,将M1与p分离,此时M1只带了一个G1;
  3. 调度器引入新的M2(新创建或已经存在的),将M2与P进行绑定,继续执行P的LRQ上的G2;
  4. G1结束堵塞操作,移回LRQ。M1空闲备用。

任务窃取(负载均衡思想)

  1. P1,P2两个P, P1的LRQ上的队列已执行完,P1的LRQ为空,P1就开始任务窃取;
  2. 如果P2的LRQ不为空,P1就从P2的LRQ上拿一半移动到自己;
  3. 如果P2的LRQ也为空,P1从GRQ窃取。

详细流程

基本流程和上面一样。每创建出一个 g,优先创建一个 p或者引入一个空闲的p 进行存储,当 p 达到限制后,则加入状态为 waiting 的队列中。

如果 g 执行时需要被阻塞,则会进行上下文切换,系统归还资源后,再返回继续执行。

当一个G长久阻塞在一个M上时,runtime会新建一个M,阻塞G所在的P会把其他的G 挂载在新建的M上。当旧的G阻塞完成或者认为其已经死掉时,则回收旧的M(抢占式调度)。

P会对自己管理的goroutine队列做一些调度(比如把占用CPU时间较长的goroutine暂停、运行后续的goroutine等等)当自己的队列消费完了就去全局队列里取,如果全局队列里也消费完了会去其他P的队列里抢任务(所以需要单独存储下一个 g 的地址,而不是从队列里获取)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go并发模型GPM 的相关文章

  • 将 Websocket 消息发送到 Go 中的特定通道(使用 Gorilla)

    我对 Go 很陌生 并且发现自己使用套接字作为我的第一个项目 这是一个多余的问题 但我无法理解如何将 websocket 更新发送到 Go 中的特定通道 使用 Gorilla 我在用此链接中的代码示例 https github com go
  • 命名和未命名类型

    问题 我最近开始阅读Golang规格手册 https golang org ref spec并陷入试图理解的困境有名和无名类型在相关部分 https golang org ref spec Types 我来自动态语言 这让我有点头疼 手册指
  • Golang 从管道读取读取大量数据

    我正在尝试读取一个正在被焦油化 流式传输到标准输入的存档 但我正在以某种方式读取far管道中的数据多于 tar 发送的数据 我像这样运行我的命令 tar cf somefolder my go binary 源代码是这样的 package
  • 无法从另一个标签的源代码构建和安装 go

    我正在尝试使用此从源代码构建和安装 go文档 https go dev doc install source 当我喜欢以下内容时 这效果很好 git clone https go googlesource com go goroot cd
  • 正则表达式不匹配

    我正在尝试以下代码 d byte x01 x00 x00 x00 x00 x00 x00 x00 x00 x00 x00 x80J x13 x80SQ x80L xe0 x80 x92 x80L x80H xe0 r regexp Must
  • 如何获取文件的 ctime、atime、mtime 并更改它们

    如何使用 Go 获取文件的 ctime mtime atime 并更改它们 在 Go 1 1 2 中 os Stat只能获取mtime os Chtimes 可以更改 mtime 和 atime 但不能更改 ctime Linux ctim
  • 从 Go Slice 中选择一个随机值

    情况 我有一些值 需要从中随机选择一个值 然后我想将它与固定字符串连接起来 到目前为止 这是我的代码 func main create the reasons slice and append reasons to it reasons m
  • java.lang.NoSuchMethodError:com.fasterxml.jackson.databind.type。使用 apache beam Spark runner 运行 go 示例时

    我想跑grades https github com apache beam tree master sdks go examples gradesapache beam go sdk 提出的示例 在一个主服务器和两个从服务器 spark2
  • GoLang - 坚持使用 ISO-8859-1 字符集

    我正在开发一个项目 我们需要将信息保存在具有 ISO 8859 1 表的旧数据库中 因此 在向数据库写入内容之前 我需要将其从 UTF 8 转换为 ISO 8859 1 每次从数据库检索它时 我都需要将其转换回 UTF 8 我试图使用图书馆
  • go 中的属性更改通知

    如何在 go 中向多个接收器发出 属性 更改信号 类似于在 Qt 中使用通知信号定义属性的方式 例如 如果您想象有一些值需要以多种方式显示 例如进度值可以同时显示为进度条和文本 当基础值发生变化时 两者都需要更新 一种方法可能是利用chan
  • 如何在 Visual Studio Code 中为 Golang 启用竞争检测器?

    我搜索了很多网页来找到我应该放入哪个短语settings json在 VS Code Golang 扩展 由 Microsoft 发布 中添加构建标志 在我的例子中是竞赛检测器 I added go buildFlags race 在扩展名
  • Go SQL查询不一致

    我在执行查询时遇到一些非常奇怪的不一致 并且想知道是否有人知道原因 想象一下我有一个定义如下的结构 type Result struct Afield string db A Bfield interface db B Cfield str
  • 无法连接到代理“证书由未知机构签名”

    我正在尝试通过 Kubernetes 部署上的 cloudsql proxy 容器连接到 CloudSQL 实例 我已安装 cloudsql 凭据以及值GOOGLE APPLICATION CREDENTIALS set 但是 我的日志中仍
  • 我们如何在 Golang 中组合多个错误字符串?

    我是 golang 新手 我的应用程序需要在循环中返回多个错误 稍后需要组合并作为单个错误字符串返回 我无法使用字符串函数来组合错误消息 在返回之前可以使用什么方法将这些错误合并为一个错误 package main import fmt s
  • 在函数中将通道作为参数传递的不同方法

    我正在阅读一些Go代码 并说了几种传递Go通道的不同方法 也许它们是相同的 但我想知道是否有任何区别 因为我无法在线找到文档 1 func serve ch lt chan interface do stuff 2 func serve c
  • 如何在C#中执行Go函数

    有没有办法从 C 执行 Go 函数 例如 对于 Python 我会使用 Ironpython 我知道我可以生成一个进程来执行 Go 脚本 但如果可能的话 我真的不想回退到这样的解决方案 Google 搜索没有显示任何内容 那么有什么方法可以
  • 在处理程序之后访问 HTTP 请求上下文

    在我的日志记录中间件 链中的第一个 中 我需要访问一些在链下游的某些身份验证中间件中编写的上下文 并且仅在处理程序本身执行之后 旁注 需要首先调用日志记录中间件 因为我需要记录请求的持续时间 包括在中间件中花费的时间 此外 当权限不足时 身
  • 在golang中获取TTFB(第一个字节的时间)值

    我正在尝试获取 TTFB 值和 Connect 值 c exec Command curl w Connect time connect TTFB time starttransfer Total time time total o dev
  • 使用 OpenTelemetry 统一不同服务的范围

    我刚刚开始使用 OpenTelemetry 并为此创建了两个 微 服务 Standard and GeoMap 最终用户将请求发送到Standard服务 该服务又将请求发送到GeoMap在将结果返回给最终用户之前获取信息 我使用 gRPC
  • Go 的范围不能超过 (类型接口 {})

    我正处于尝试将我的注意力集中在 Go 上的婴儿阶段 目前 我正在模拟一个 API 请求 该请求返回包含对象数组的 JSON 格式的字符串 我试图找出迭代每个记录并访问每个字段的最合适的方法 最终 每个字段都将写入 Excel 电子表格 但现

随机推荐

  • 电脑性能一目了然,教你用测试软件测试整机性能

    一台笔记本电脑或者是一台DIY台式电脑 都是由处理器 显卡 硬盘等配件构成 而每个配件都有自己的性能 性能是高是低我们可以进行单项测试 对于整机性能我们也可以对其进行测试 来看看它的真实性能到底如何 CPU中文名叫中央处理器 它是一台电脑中
  • Java多线程并行处理任务的实现

    Java多线程并行处理任务的实现 在实际项目开发的过程中 遇到过需要处理一个由多个子任务组成的任务的问题 顺序处理起来会造成响应时间超长 用户体验不好的问题 我想到一个解决方案 即使用多线程并行处理子任务 思路就是使用ThreadPoolE
  • 微信小程序 web-view 访问外部链接

  • mysql(8.0.27)本地启动没有问题,远程无法连接解决方案+开启远程连接+问题排查路径

    目录标题 mysql安装 现象 错误排查 mysql安装 mysql8 0 27 免安装教程连接 安装教程连接 现象 1 mysql本地启动正常 C Users youc gt mysql u root p Enter password W
  • NC22 合并两个有序的数组 - java语言实现

    文章目录 1 题目描述 2 题目解读 3 思路 4 代码实现 总结 学习的道路很枯燥 希望我们能并肩走下来 编程真是一件很奇妙的东西 你只是浅尝辄止 那么只会觉得枯燥乏味 像对待任务似的应付它 但你如果深入探索 就会发现其中的奇妙 了解许多
  • Visual Studio 性能探查器使用技巧,看这篇就足够了

    Visual Studio 提供了性能测量值和分析工具选择 某些工具 如 CPU 使用情况 和 内存使用情况 可以在带或不带调试器的情况下运行 也可以在发布版本或调试版本配置上运行 应用程序时间线 等 性能探查器 工具可以在发布版本或调试版
  • YUM安装软件包(联网+断网两种)

    Yum 全称为 Yellow dog Updater Modified 是一个在Fedora和红帽 RedHat 以及CentOS中的Shell前端软件包管理器 基于RPM包管理 能够从指定的服务器自动下载RPM包并且安装 可以自动处理依赖
  • MySQL与常见面试题

    目录 事务 概述 ACID AUTOCOMMIT 总结 并发一致性问题 丢失修改 读脏数据 不可重复读 幻读 原因和解决方法 隔离级别 未提交读 READ UNCOMMITTED 提交读 READ COMMITTED 可重复读 REPEAT
  • 端口查看(非原创)

    端口查看 非原创 1 Netstat命令用法 命令格式 Netstat a e n o s an a 表示显示所有活动的TCP连接以及计算机监听的TCP和UDP端口 e 表示显示以太网发送和接收的字节数 数据包数等 n 表示只以数字形式显示
  • c# .net mvc的IHttpHandler奇妙之旅。.net的生命周期和管道你听说过吗?你可以利用他处理业务如:跳转业务页面,文件请求的安全过滤,等等,还有许多神秘业务等着你去发现

    源码下载 c net mvc图片文件请求安全过滤 图片防盗链 https download csdn net download cplvfx 88206428 c net mvc的IHttpHandler奇妙之旅 net的生命周期和管道你听
  • TensorRT部署YOLOv5(02)-环境介绍

    本文对TensorRT部署YOLOv5模型的整体环境配置及软件包进行介绍 实验环境主要从主机和JestonNano两方面进行介绍 在主机端完成模型训练并转换为onnx中间模型表示 在JestonNano进行onnx模型转换为TensorRT
  • cocos2dx 3.0 新建工程

    打开终端 转到cocos2d 3 0的这个目录下tools cocos2d console bin cocos py cocos py 运行命令 会显示该命令的帮助 根据帮助提示进行操作 有以下几个命令可用 compile Compiles
  • 游戏开发unity编译和调试系列:Unsafe code may only appear if compiling with /unsafe

    问题 Unsafe code may only appear if compiling with unsafe Enable Allow unsafe code in Player Settings to fix this error 解决
  • MySQL中的锁机制和MVCC

    MySQL中的锁和MVCC 概述 InnoDB的MVCC MVCC锁相关 SQL语句的加锁分析 RR隔离级别是如何解决幻读的 死锁 模拟死锁 在学习MySQL中的锁机制相关时搜集了几篇写得非常不错的博客 这里就不再花时间详细介绍 本篇仅做总
  • 批量异步更新策略及 nextTick 原理?

    在Vue中 当需要对多个响应式数据进行异步更新时 可以使用 批量异步更新策略 Vue在更新组件状态时 会将所有的异步更新合并成一个批量更新 从而避免不必要的重复渲染和提高性能 Vue中的异步更新策略是基于 事件循环 Event Loop 的
  • numpy 索引和切片

    目录 1 索引元素 2 切片 省略参数写法 3 应用举例 4 多维数组 二维数组获取一行 二维数组获取一列 5 多维数组的切片 如果要获取 第一行的第四和第五个元素 如果得到数组的最后两行和最后两列 如果得到数组的第三列 如果取出第3 5行
  • (局部特征)HOG+SVM,LBP,Haar

    在利用多幅二维图像进行三维重建 恢复场景三维结构的应用中 其基本出发点是要有一个可靠的图像对应点集合 而自动地建立图像之间 点与点之间的可靠对应关系通常都依赖于一个优秀的局部图像特征描述子 在物体识别中 目前非常流行以及切实可行的方法之一是
  • 记录QT4键盘无法置顶问题

    键盘类设置 QWidget setWindowFlags windowFlags Qt WindowStaysOnTopHint Qt FramelessWindowHint Qt X11BypassWindowManagerHint 莫名
  • bash脚本,自动输入sudo的密码

    解决方法 echo 管道 开始使用 echo admin sudo service tomcat7 stop 始终提示输入密码 后来查看了下sudo命令的使用 man sudo 发现有如下的解释 S The S stdin option c
  • go并发模型GPM

    线程模型的三种实现方式 用户级线程 M 1对应关系 多个用户态线程对应着一个内核线程 用户态线程的创建 终止 切换 同步等线程工作必须由自身来完成 内核级线程 1 1对应关系 直接调用操作系统的内核线程 所有线程的创建 终止 切换 同步等操