Go学习笔记—并发高级

Go并发机制

​ 协程:一个线程可以对应多个协程,协程串行运行在用户空间。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。

​ Go摒弃线程、进程、协程,提出goroutine:

  • M(machine):一个M代表一个内核线程(与KSE一一对应)
  • P(processor):一个P代表执行一个Go代码片段所必须的资源(上下文环境)
  • G(goroutine):一个G代表一个Go代码片段。

​ 一个M与一个P关联之后,就形成一个G的运行环境(内核线程+上下文环境)。M与KSE一对一,M与P总是一对一(当一个M因系统调用阻塞(运行的G进入系统调用),此时P会与M分离开来,并与新建/空闲的M关联),P与G一对多

操作作用
runtime/debug.SetMaxThreads设置M的最大数量
runtime.GOMAXPORCS设置P的最大数量(可运行G队列的数量)

在这里插入图片描述

一、M、P、G

——M(Machine)

​ 系统维护一个全局M列表(runtime.allm) 调度器维护一个空闲M列表(runtime.sched.midle)

——P(Processor)

​ 系统维护一个全局P列表(runtime.allp) 调度器维护一个空闲P列表(runtime.sched.pidle)

​ 每个P维护一个可运行G队列(runtime.p.runq)(队列满则会分出一半给调度器可运行G队列)与一个自由G列表(runtime.p.gfree)(已经运行完成的G,在欲启用一个go语句时,会复用该列表中的G。当P中的自由G列表元素过多或过少时,调度器的自由G列表会与其进行转移)

状态说明
Pidle当前P未与任何M存在关联
Prunning当前P正在与某个M关联
Psyscall当前P中运行的那个G正在进行系统调用
Pgcstop运行时系统需要停止调度(系统开始垃圾回收的一些步骤,会将全部P设为此状态)
Pdead当前P已经不会再被使用(调整最大P数量后,多余的P会被设为此状态)

在这里插入图片描述
​ 非dead状态的P在系统欲停止调度时都会被置于Pgcstop状态。等到需要重启调度时,会被统一置于Pidle状态,即公平的接受再次调度。同时进入dead状态的P,其可运行的G与自由的G都会被转移到调度器的可运行G列表与自由G列表中。

——G(goroutine例程)

​ 系统维护一个全局G列表(runtime.allgs)

​ 调度器维护一个可运行G列表(runtime.sched.runqhead runtime.sched.runqtail) 一个自由G列表(runtime.sched.gfreeStack runtime.sched.gfreeNoStack)

状态说明
Gidle刚被新分配,还未初始化
Grunnable正在可运行队列中等待运行
Grunning当前G正在运行
Gsyscall当前G正在执行系统调用
Gwaiting当前G正在阻塞
Gdead当前G正在闲置
Gcopystack当前G的栈正在被移动


​ Gdead不同于Pdead,前者可以加入自由列表等待再次复用,后者只会被销毁。

二、调度器

​ Go调度器不是运行在某个专用内核线程中的程序,调度器会运行在几乎所有已存在的M(内核线程)中。

​ 调度器基本数据结构:空闲M列表,空闲P列表,可运行G队列,自由G列表,此外还有几个重要字段与需要停止调度的任务(Stop the world,STW)有关。

字段名数据类型作用
gcwaitinguint32是否需要因一些任务而停止调度(比如垃圾回收)
stopwaitint32需要停止但仍未停止的P数量
stopnotenote实现与stopwait相关的事件通知机制

​ 在停止调度前,gcwaiting被置为1,调度任务在发现这一状态后,将当前P状态置为Pgcstop并将stopwait字段减一。当stopwait减为0时,说明所有P已置为Pgcstop,此时利用stopnote唤醒待执行的任务(比如垃圾回收),之后恢复gcwaiting为0。

字段名数据类型作用
sysmonwaitunit32在停止调度期间系统监控任务是否在等待
sysmonnotenote实现与sysmonwait相关的事件通知机制

​ 这两个字段针对系统监测任务,即在执行需要停止调度的任务之前,也需要停止系统监测任务。系统监测程序发现所有P都已经闲置或gcwaiting不为0,会将sysmonwait置为1,并使用sysmonnote暂停自身,结束后,再恢复这两个状态。

一轮调度

​ 在启动Go程序并完成初始化后,会启动一轮调度使得封装了main函数的G可以被调度运行,在G运行阻塞、结束、退出系统调用后都会引发一轮调度。

  • M与G的成对锁定,是为了CGO准备。即C的函数库会将数据存储于内核线程,所以为了放止数据丢失,只能在一段时期内将G与特定M进行关联。

  • 当调度器为某个M1寻找到可执行G,但是检查到某个M2已经与该G锁定,则会立刻停止调度并停止M2,并将G交由M2运行(实际上是把M1的P交由M2),M1则寻找其他可执行G。——这意味着M2在运行锁定的G前,不会做其他事,即资源被浪费。

  • 全力查找可运行的G:若还未找到G,则调度器会停止该M,并在以后特定时刻唤醒重新查找。还未找到可运行G的M称为自旋状态

  • 启用或停止M

    (1)调度器调度一个M会预先检查其是否与某个G锁定;如果有,则会调用stoplockedm解除当前M与P的关联并将P转手,并暂停当前M的执行。

    (2)调度器为M发现一个可运行的G,但是该G已经被其他M锁定。会调用startlockedm将本地M的P转手给锁定的M,并暂停本地M的运行。放入空闲M列表。

    (3)调度器发现有STW任务时,会调用gcstopm停止当前M。即释放本地P(置为Pgcstop)并调用stopm。

    (4)只有当有新工作,并且由空闲P时,调用startm才可以执行一个M。

    操作作用
    stopm()停止当前M的执行
    gcstopm()为STW任务让路,停止当前M,执行完毕后会被唤醒
    stoplockedm()停止已与某个G锁定的M的执行,直到这个G可运行
    startlockedm(gp *g)唤醒与gp锁定的那个M
    startm(p *p, spining bool)唤醒或创建一个M去关联P并开始执行
三、其他几个要点

——g0、m0

​ g0:系统中每个M拥有的特殊G。g0所拥有的内存称为M的调度栈,对应于内核中线程的栈,即OS线程栈。用于执行调度、垃圾回收、栈管理等。

​ gsignal:系统中每个M拥有的特殊G,用来处理信号。即信号栈

​ m0:Go程序的第一个内核线程runtime.g0,用于执行引导程序。

——调度器锁和原子操作

​ 每个M都有可能执行调度任务,而这些任务可能会并发进行,所以需要在读写一些全局变量时进行调度器锁保护。比如sched.stopwait(STW任务时记录需要停止的M)、sched.nmidle(对空闲M计数)、对核心元素容器进行存取(runtime.allp, runtime.sched.runqhead)。

​ 同时也采用原子操作保护一些变量。比如sched.spining(对自旋M计数)、sched.ngsys(对系统G计数)、切换G状态。

——调整GC

​ Go的GC基于CMS(Concurrent Mark-Sweep)算法。调度器会适时调度GC相关任务执行,系统监测任务也会在必要时强制执行。有三种执行模式:

  • gcBackgroundMode:并发执行垃圾收集和清扫。
  • gcForceMode:串行的执行垃圾收集(即执行时停止调度),并发的执行垃圾清扫。
  • gcForceBlockMode:串行的执行垃圾收集和清扫。

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

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

相关文章

设计模式C++学习笔记之十三(Decorator装饰模式)

装饰模式,动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。 13.1.解释 main(),老爸 ISchoolReport,成绩单接口 CFourthGradeSchoolReport,四年级成绩单 ReportDecorator&…

Android应用开发相关下载资源(2014/12/14更新)

官方终于发布了Android Studio正式版,Android Studio将会成为推荐使用的主要Android开发工具. (1)Android SDK (Android SDK主安装包,包含SDK Manager、AVD Manager、工具包tools,释放后的根文件夹为android-sdk-windows): revision 23.0.2ht…

分层在深一步学习

前几天自己写了写DAL层,还有Model!理解到在DAL中主要是写的数据操作,而这些操作又是基于DbHelper这个基类!而数据库的访问则写在了这个基类中,目前还没研究BLL层,不过知道其中写的是算法!在Model中写的对象的属性,还有数据的规范(据说是,呵呵).自己对分层开发很感兴趣!呵呵,加油…

程序员编程艺术:第二章、字符串是否包含问题

程序员编程艺术:第二章、字符串是否包含及相关问题扩展 作者:July,yansha。时间:二零一一年四月二十三日。致谢:老梦,nossiac,Hession,Oliver,luuillu,雨翔&a…

LeetCode—207. 课程表

207. 课程表 题目描述:你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] [ai, bi] ,表示如果要学习课程 ai…

详解为何在嵌套ESXi环境下要求开启Promiscuous Mode

原文链接:http://bbs.vmanager.cn/forum.php?modviewthread&tid8688&fromuid35445在嵌套环境中,有时候网路不通,此时,调整Promiscuous Mode选项为Accept之后,网路就可以通了。之前只是知道这个选项可以保证嵌…

Rapidmind计算库性能测试

rapidmind.net提供了免费的计算库下载,目的是使用C metaprogramming将计算与硬件平台隔离开来,它提供一套运行库做底层的优化工作。为了测试其真正的性能,以便于在未来的渲染器中使用,我做了一个简单的性能测试程序,将…

VMware 怎么进入BIOS

2019独角兽企业重金招聘Python工程师标准>>> 虚拟机(Vmware)引导Linux虚拟机时,需要设置成光盘启动来引导系统,但是vmware默认是硬盘启动,所以会启动不了或者别的问题存在。所以要进bios里面设置成开机的启动顺序,要将…

LeetCode—208. 实现 Trie (前缀树)

208. 实现 Trie (前缀树) 题目描述:Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。 请你实现 Trie 类…

SQL入侵恢复XP_CMDSHLL与开3389

一,用SQL连接器恢复XP_CMDSHLLE的命令 (1)sp_addextendedproc xp_cmdshell,dllnamexplog70.dll (2)首先在SqlExec Sunx Version的Format选项里填上%s,在CMD选项里输入 sp_addextendedproc xp_cmdshell,xpsql70.dll 去除…

java中long类型转换为int类型

由int类型转换为long类型是向上转换,可以直接进行隐式转换,但由long类型转换为int类型是向下转换,可能会出现数据溢出情况: 主要以下几种转换方法,供参考:一、强制类型转换 [java] long ll 300000; in…

中国最好的电子商务平台,75商务网成功上线

中国B2B电子商务网站多年处于停滞不前,行业垄断现象,而且非常专注于B2B方向发展,没有其他业务范围可以拓展。http://www.755563.com/ “ 75商务网 ”看到其中亮点,在原有B2B基础上增加新型模式,变成B2B2C形式&#xff…

SVN钩子HOOK设置自动备份,服务本地可以看到所有更新内容。

可以实现SVN本机备份。或者其他备份。关键是可以保持有一份最新的SVN文件可以查看。 实现SVN与WEB同步,可以CO一个出来,也可以直接用自动更新web目录的方法,我们要在svn版本库中配置钩子来实现,就是创建一个post-commit的配置文件,对其进行简…

LeetCode—33. 搜索旋转排序数组

33. 搜索旋转排序数组 题目描述&#xff1a;整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums…

巧用脚本为木马“整容”

目的&#xff1a; 掌握基础的VBS脚本&#xff0c;“改变”木马后缀名不引起警觉&#xff0c;他点击木马后会先运行一段我们装备好的素材&#xff0c;音乐或图片&#xff0c;然后才执行木马 诱骗对方运行木马 前工作&#xff1a;根据需要准备一款木马&#xff0c;一个ICO图标文件…

重读STL

从第一次使用STL到现在也有四年了&#xff0c;说来惭愧&#xff0c;以前一直只是现用现查&#xff0c;还从来没有仔细地读一读STL的文档。前两天偶尔看到一个别人推荐的链接&#xff08;http://www.sgi.com/tech/stl/&#xff09;&#xff0c;才想起应该看看&#xff0c;一读之…

OSChina 周四乱弹 —— 熊孩子毁灭世界

2019独角兽企业重金招聘Python工程师标准>>> 小伙伴们赶快起床&#xff0c;开源中国要出大事啦~ 为方便大家搜索开源软件&#xff0c;开源中国决定整理 IT 公司开源软件。初步列表不一定完善&#xff0c;小伙伴们有什么意见可以向小小编或者红薯提出来~ 好啦好啦&am…

华为EC169 3G卡在Win7下的安装

最近换了机器&#xff0c;安装的是Win7。结果发现安装华为EC169 3G卡时&#xff0c;无法安装。&#xff08;注&#xff1a;我已更新为最新支持Win7的驱动。&#xff09; 折腾了近半天的时间&#xff0c;才发现是内码的问题。 由于工作需要&#xff0c;我将非Unicode的内码改为了…

小容量单片机生成pdf文件

工作上要求使用小容量单片机生成直接生成pdf文件。经过一段时间的摸索&#xff0c;其中参考了libharu&#xff0c;库太大&#xff0c;不适合在单片机上使用页参考了与非网上一位前辈的库&#xff0c;占用的RAM太大&#xff0c;不适合小容量单片机&#xff0c;主要资料是pdf1.7格…

LeetCode—209. 长度最小的子数组

209. 长度最小的子数组 题目描述&#xff1a;给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0…