GO学习之 goroutine的调度原理

GO系列

1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)
7、GO学习之 多线程(goroutine)
8、GO学习之 函数(Function)
9、GO学习之 接口(Interface)
10、GO学习之 网络通信(Net/Http)
11、GO学习之 微框架(Gin)
12、GO学习之 数据库(mysql)
13、GO学习之 数据库(Redis)
14、GO学习之 搜索引擎(ElasticSearch)
15、GO学习之 消息队列(Kafka)
16、GO学习之 远程过程调用(RPC)
17、GO学习之 goroutine的调度原理

文章目录

  • GO系列
  • 前言
  • 一、goroutine 调度器
  • 二、goroutine调度模型与演进过程
    • 2.1 G-M 模型
    • 2.2 G-P-M 模型
    • 2.3 抢占式调度
    • 2.4 NUMA调度模型
  • 三、goroutine 调度器原理
  • 四、调度器状态查看
  • 五、小结

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
并发与并行:21世纪以后,数据中心的硬件和网络环境发生了重大变化,多核处理器硬件成为数据中心的主流。而20世纪的主流编程语言(C++,java等)并非以解决多核和网络环境下日益复杂的问题而生,即便这些语言在后续的版本中努力做了有针对性的改善,但毕竟积重难返,其最初的语音设计决定了开发人员想要有效地利用多核环境的强大计算能力,要付出的心智负担依旧很好。

  • 并行方案:就是在处理核数充足的情况下启动多个单线程应用的实例
  • 并发方案:并发就要从小做应用结构设计,即将应用分解成多个在基本单元中执行,可能有一定关联关系的代码片段。

Go 语言的设计哲学之一是 “原生并发,轻量高效”。Go 并未使用操作系统线程作为分解后的代码片段的基本执行单元,而是实现了 goroutine 这一由Go运行时负责调度的用户层轻量级线程为并发程序设计提供原生支持。
goroutine相比传统操作系统线程而言具有如下优势:

  1. 资源占用小,每个 goroutine 的初始栈大小仅为 2KB
  2. 由 Go 运行时而不是操作系统调度,goroutine 上下文切换代价小。
  3. 语言原生支持:goroutine 由 Go 关键字函数或方法创建,函数或方法返回即表示 goroutine 退出,开发体验更佳。
  4. 内置 channel 作为 goroutine 间通信原语,并并发设计提供强大支撑。

—— 以上内容摘自《Go语音精进之路》一书。
Go语言精进之路
此篇内容也是借鉴此书而写。

一、goroutine 调度器

什么是 goroutine调度器呢?提到 “调度”,想到的就是有一个中央控制器,对资源的各种调度以达到某种目的,比如操作系统对进程、线程的调度。操作系统调度器会将操作系统中的多个线程按照一定的算法调度到物理CPU上运行。传统的编程语言的并发实现多试基于线程模型的,即应用程序负责创建线程,操作系统负责调度线程。然而这种传统支持并发的方式有诸多不足,比如:使用复杂、线程安全、难以扩展等。
为此,Go 采用用户层轻量级线程来解决这些问题,并称之为 goroutine
由于 goroutine 占用资源很少,一个 Go 程序中可以创建上万个并发的 goroutine。而将这些 goroutine 按照一定的算法放到 CPU 上执行的程序就称之为 goroutine 调度器
一个 Go 程序对于操作系统来说只是一个用户层程序,操作系统只有线程, goroutine 的调度全要靠 Go 自己完成。

二、goroutine调度模型与演进过程

2.1 G-M 模型

Go 1.0正式版本中,Go 开发团队实现了一个简单的 goroutine 调度器。这个调度器中,每个 goroutine 对应与运行中的一个抽象结构 —— G(goroutine),而被视作 “物理CPU” 的操作系统线程则被抽象为另一个结构 —— M(machine)。这个模型比较简单且能正常工作,但存在着诸多问题。

原文如下:
前英特尔黑带级工程师、现谷歌工程师Dmitry Vyukov在“Scalable Go Scheduler Design”一文中指出了G-M模型的一个重要不足:限制了Go并发程序的伸缩性,尤其是对那些有高吞吐或并行计算需求的服务程序
问题主要体现在如下几个方面。

  • 单一全局互斥锁(Sched.Lock)和集中状态存储的存在导致所有goroutine相关操作(如创建、重新调度等)都要上锁。
  • goroutine传递问题:经常在M之间传递“可运行”的 goroutine 会导致调度延迟增大,带来额外的性能损耗。每个M都做内存缓存,导致内存占用过高,数据局部性较差。

因系统调用(syscall)而形成的频繁的工作线程阻塞和解除阻塞会带来额外的性能损耗。

2.2 G-P-M 模型

在发现了 G-M 模型的不足后,这位大佬(Dmitry Vyukov)改进了 goroutine 调度器,实现了 G-P-M 调度模型 和 work stealing 算法,如图所示:
G-P-M调度模型
这位大佬向 G-M 模型中增加了一个 P,使得 goroutine 调度器具有很好的伸缩性。
那 P 是什么?P 是一个 “逻辑处理器”,每个 G 想要真正运行起来,首先需要分配一个 P,即进入P 的 本地运行队列(local runq)中。对于 G 来说,P 就是运行它的 “CPU”,可以说在 G的眼里只有 P。但从 goroutine 调度器的视角来看,真正的 “CPU” 是 M。只有将 P 和 M 绑定才能让 P 的本地运行队列中的 G 真正运行。这样一来 P 与 M 的对应关系是 多对多(N:M)。

2.3 抢占式调度

在实现了 G-P-M 调度模型这一大进步之后,调度器仍然有一个头疼的问题,那就是不支持抢占式调度,这导致一旦某个 G 中出现死循环的代码逻辑,那么 G 将永久占用分配给它的 P 和 M,而位于同一个 P 中的其他 G 将得不到调度,出现 “饿死” 情况。
于是大佬又提出了 “抢占式调度” 设计, 并在 Go 1.2 版本中实现了抢占式调度。

这个抢占式调度的原理是在每个函数或方法的入口加上一段额外的代码,让运行时有机会检查是否需要执行抢占调度。这种协作式抢占调度的解决方案只是局部解决了“饿死”问题,对于没有函数调用而是纯算法循环计算的G,goroutine调度器依然无法抢占

2.4 NUMA调度模型

在 Go 1.2 以后,Go 重点放在了 GC 低延迟的优化上,大佬虽然提出了 NUMA 调度模型,但没有真正落地实现,还有待考察。

三、goroutine 调度器原理

  1. G P M 介绍

G:代表goroutine,存储了goroutine的执行栈信息、goroutine状态及goroutine的任务函数等。另外G对象是可以重用的。
P:代表逻辑processor,P的数量决定了系统内最大可并行的G的数量(前提:系统的物理CPU核数>=P的数量)。P中最有用的是其拥有的各种G对象队列、链表、一些缓存和状态。
M:M代表着真正的执行计算资源。在绑定有效的P后,进入一个调度循环;而调度循环的机制大致是从各种队列、P的本地运行队列中获取G,切换到G的执行栈上并执行G的函数,调用goexit做清理工作并回到M。如此反复。M并不保留G状态,这是G可以跨M调度的基础。

  1. G 被抢占调度
    与操作系统按时间片调度线程不同,Go 中并没有时间片概念。如果某个 G 没有进行系统调用(syscll)、没有进行 I/O 操作,也没有阻塞在一个 channel 操作上,那么 M 是如何让 G 停下来并调度下一个可运行的G 呢?
    答案是:G 是被抢占调度的

  2. channel阻塞 或者 网络I/O 情况下的调度
    如果 G 被阻塞在某个 channel操作 或者 网络I/O 操作上,那么 G 会被放置在某个等待队列中,而 M 会尝试运行 P 的下一个运行的 G。
    如果此时 P 没有可运行的 G 提供 M 运行,那么 M 将解绑 P,并进入挂起状态。
    当 I/O 操作 或者 channel操作完成,在等待队列中的 G 会被唤醒,标记为 runnable 状态,并进图某个 P 的队列中,绑定一个 M 后继续执行。

  3. 系统调用阻塞情况下的调度
    如果 G 被阻塞在某个系统调用上,那么不仅 G 会阻塞,执行该 G 的 M 也会解绑 P,与 G 一起进入阻塞状态;如果此时有空闲的 M,则 P 会与其绑定并继续执行其他 G;如果没有空闲的 M,但任然有其他 G 要执行,那么就会创建一个新 M;
    当系统调用返回后,阻塞在该系统调用上的 G 会尝试获取一个可用的 P,如果有可用 P,之前运行该 G 的 M 将绑定 P 继续运行 G。如果没有可用的 P,那么 G 与 M 之间的关系将解绑,同时 G 会被标记为 runnable,放入全局的运行队列中,带的调度器的再次调度。

四、调度器状态查看

Go提供了调度器当前状态的查看方法:使用Go运行时环境变量GODEBUG
关于Go调度器调试信息输出的详细信息,可以参考Dmitry Vyukov的文章 Debugging Performance Issues in Go Programs,这也应该是每个Gopher必读的经典文章。
更详尽的信息可参考$GOROOT/src/runtime/proc.go中schedtrace函数的实现。

五、小结

goroutine是Go语言并发的基础,也是最基本的执行单元。Go基于goroutine建立了G-P-M的调度模型,了解这个调度模型对于Go代码设计以及Go代码问题的诊断都有很大帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zebec Protocol 薪酬支付工具 WageLink 上线,掀新一轮薪酬支付浪潮

Zebec Protocol 正在从多个方面推动流支付的应用,除了作为一种全新的支付手段来对支付领域进行重塑外,其也在以流支付体系为基础,不断地向薪酬发放领域深度的拓展。 在今年早些时候,Zebec Protocol 通过美国投资机构 Payroll Grow…

【FISCO-BCOS】十八、使用docker部署区块链

目录 前言: docker: 一、安装docker docker部署区块链: 一、 搭建单群组4节点区块链 二、启动区块链 三、检查容器 四. 查看节点 前言: 关于FISCOBCOS部署区块链的方式,我们已经学习过了很多种,如多群组部…

现代C++、STL、QTL的使用

0、现代C中最重要的是&#xff1a; 右值引用&&、移动语义std::move、完美转发std::forward、万能引用T&& void Func(int& x) { cout << "左值引用" << endl; } void Func(const int& x) { cout << "const左值引用…

软件测试之【单元测试、系统测试、集成测试】

一、单元测试的概念 单元测试&#xff08;Unit Testing&#xff09;是对软件基本组成单元进行的测试&#xff0c;如函数&#xff08;function或procedure&#xff09;或一个类的方法&#xff08;method&#xff09;。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff…

volatile-可见性案例详解

6.3 volatile特性 6.3.1 保证可见性 保证不同线程对某个变量完成操作后结果及时可见&#xff0c;即该共享变量一旦改变所有线程立即可见 不加volatile&#xff0c;没有可见性&#xff0c;程序无法停止 加了volatile&#xff0c;保证可见性&#xff0c;程序可以停止 public…

RHCE---Shell基础 2

文章目录 目录 文章目录 前言 一.变量 概述 定义 自定义变量 环境变量 概述&#xff1a; 定义环境变量&#xff1a; 位置变量 "$*"会把所有位置参数当成一个整体&#xff08;或者说当成一个单词 变量的赋值和作用域 read 命令 变量和引号 变量的作用域 变…

基于拦截器Interceptor实现简易权限控制及行为记录功能

一、业务需求 使用拦截器(Interceptor)&#xff0c;实现Controller中方法的权限控制&#xff0c;并记录访问行为。要求仅在Controller方法上加注解&#xff0c;就可以实现权限控制。具体为&#xff1a; 1、拦截未登录用户的访问&#xff1b; 2、拦截不具有权限用户的访问&#…

Git教程

文章目录 Git 介绍GIt历史Git 安装环境配置工作区、缓存区和仓库区&#xff08;版本库&#xff09;工作区(工作目录)暂存区仓库区git工作目录下文件的装填 Git 生成公钥及添加到gitlab或Gerrit上Git常用命令git stautsgit statu -sgit addgit commitgit reset1. git reset --ha…

Post-Process1-水下

一、新建第三人称游戏项目&#xff0c;我这里选择C&#xff0c;你也可以选择Blueprint。 新建一个Level&#xff0c;命名为DemoUnderWater 保存一下&#xff0c;命名为DownUnderWater 添加水插件 选择Yes 勾选Show Engine Content和Show Plugin Content&#xff0c;在左侧可以看…

图(graph)的遍历----深度优先(DFS)遍历

目录 前言 深度优先遍历&#xff08;DFS&#xff09; 1.基本概念 2.算法思想 3.二叉树的深度优先遍历&#xff08;例子&#xff09; 图的深度优先遍历 1.图(graph)邻接矩阵的深度优先遍历 思路分析 代码实现 2.图(graph)邻接表的深度优先遍历 思路分析 代码实现 递…

【Web】| CSS Float (浮动)的使用方法

Float&#xff08;浮动&#xff09;概念 CSS的Float&#xff08;浮动&#xff09;&#xff0c;会使得元素向左或者向右移动&#xff0c;其它周围元素也会重新排列。 Float浮动&#xff0c;往往是用于图像&#xff0c;但它的布局一样非常有效。 元素如何浮动 元素的水平方向…

【MySQL架构篇】MySQL字符集、大小写规范及默认数据库

文章目录 1. 字符集与字符集比较规则2. 大小写规范3. 默认数据库4. 与文件系统相关 1. 字符集与字符集比较规则 MySQL有4个级别的字符集和比较规则&#xff0c;分别是 服务器级别数据库级别表级别列级别 当创建对应表或列未指定字符集时&#xff0c;默认会取其上一级别的字符…

MySQL中的表操作,配置文件,储存引擎,数据类型

MySQL中的表操作 1 查库&#xff08;已密码登陆mysql&#xff09; show databases; 2 添加库 create database t1; 3 表操作 1选定操作库 use t1 2在库里添加表格式 create table t1(id int, name varchar(32), gender varchar(32),age int); 3往表里添加具体元素 insert…

OpenCV 笔记(2):图像的属性以及像素相关的操作

Part11. 图像的属性 11.1 Mat 的主要属性 在前文中&#xff0c;我们大致了解了 Mat 的基本结构以及它的创建与赋值。接下来我们通过一个例子&#xff0c;来看看 Mat 所包含的常用属性。 先创建一个 3*4 的四通道的矩阵&#xff0c;并打印出其相关的属性&#xff0c;稍后会详细…

django建站过程(2)创建第一个应用程序页面

创建第一个应用程序页面 设置第一个页面【settings.py,urls.py,views.py】settings.pyurls.pyviews.py django是由一系列应用程序组成&#xff0c;协同工作&#xff0c;让项目成为一个整体。前面已创建了一个应用程序baseapp,使用的命令 python manage.py startapp baseapps这…

2023全新小程序广告流量主奖励发放系统源码 流量变现系统

2023全新小程序广告流量主奖励发放系统源码 流量变现系统 分享软件&#xff0c;吃瓜视频&#xff0c;或其他资源内容&#xff0c;通过用户付费买会员来变现&#xff0c;用户需要付费&#xff0c;有些人喜欢白嫖&#xff0c;所以会流失一部分用户&#xff0c;所以就写了这个系统…

RustCC分享会|非凸科技与开发者共同探讨Rust安全进化

10月15日&#xff0c;非凸科技受邀参加RustCC联合多家开发者社区组织的Global Tour of Rust技术分享活动&#xff0c;旨在为Rust开发者提供交流互动的平台&#xff0c;分享Rust语言的知识、经验和最佳实践。 活动上&#xff0c;非凸科技成都分公司研发总监赵海峰以“Rust安全进…

系统架构师备考倒计时13天(每日知识点)

1. 数据仓库四大特点 面向主题的。操作型数据库的数据组织面向事务处理任务&#xff0c;各个业务系统之间各自分离&#xff0c;而数据仓库中的数据是按照一定的主题域进行组织的。集成的。数据仓库中的数据是在对原有分散的数据库数据抽取、清理的基础上经过系统加工、汇总和整…

TechSmith Camtasia 2023 for Mac 屏幕录像视频录制编辑软件

​ TechSmith Camtasia for Mac 2023中文破解版 是一款专业的屏幕录像视频录制编辑软件&#xff0c;非常容易就可以获得精彩的截屏视频。创建引人注目的培训&#xff0c;演示和演示视频。Camtasia 屏幕录制软件简化&#xff0c;直观&#xff0c;让您看起来像专业人士。利用Camt…

安卓使用android studio跨进程通信之AIDL

我写这篇文章不想从最基础的介绍开始,我直接上步骤吧. 1.创建服务端 1.1:创建服务端项目:我的as版本比较高,页面就是这样的 1.2:创建AIDL文件,右键项目,选中aidl aidl名字可以自定义也可以默认 basicTypes是自带的,可以删掉,也可以不删,然后把你自己所需的接口写上去 1.3:创建…