弄懂goroutine调度原理
goroutine简介
golang语言作者Rob Pike说,“Goroutine是一个与其他goroutines 并发运行在同一地址空间的Go函数或方法。一个运行的程序由一个或更多个goroutine组成。它与线程、协程、进程等不同。它是一个goroutine“。
- goroutine通过通道来通信,而协程通过让出和恢复操作来通信;
- goroutine 通过Golang 的调度器进行调度,而协程通过程序本身调度;
简单的说就是Golang自己实现了协程并叫做goruntine(本文称Go协程),且比协程更强大。
goroutine调度原理
上面说到Go协程是通过Golang的调度器进行调度的,其中调度器的线程模型为两级线程模型。
有关两级线程模型的介绍,可以看这篇文章
我们来看下Golang实现的两级线程模型是怎样的。首先要知道这三个字母代表的含义
- M:代表内核级的线程
- P:全程Processor,代表运行Go协程所需要的资源(上下文环境)
- G:代表Go协程
我们先看下为实现调度Golang定义了这些数据结构存M,P,G
名称 | 作用范围 | 描述 |
---|---|---|
全局M列表 | Go的运行时 | 存放所有M的单向链表 |
全局P列表 | Go的运行时 | 存放所有P的数组 |
全局G列表 | Go的运行时 | 存放所有G的切片 |
调度器的空闲M列表 | 调度器 | 存放空闲M的单向链表 |
调度器的空闲P列表 | 调度器 | 存放空闲P的单向链表 |
调度器的自由G列表 | 调度器 | 存放自由G的单向链表(有两个) |
调度器的可运行G队列 | 调度器 | 存放可运行G的队列 |
P的自由G列表 | 本地P | 存放当前P中自由G的单向链表 |
P的可运行G队列 | 本地P | 存放当前P中可运行G的队列 |
然后从上往下解析Go的两级线程模型图
(1)M和内核线程之间是一对一的关系,一个M在其生命周期中,只会和一个内核线程关联,所以不会出现对内核线程的频繁切换;
Golang的运行时执行系统监控和垃圾回收等任务时候会导致创建M,M空闲时不会被销毁,而是放到一个
调度器的空闲M列表
中,等待与P关联,M默认数量为10000
(2)P和M之间是多对多的关系,P和G之间是一对多的关系,他们的关联是易变的,由Golang的调度器完成调度;
Golang的运行时按规则调度,让P和不同的M建立或断开关联,使得P中的G能够及时获得运行时机
(3)P的数量默认为CPU总核心数,最大为256,当P没有可运行的G时候(P的可运行G队列为空),P会被放到调度器的空闲P列表
中,等待M与它关联;
P有可能会被销毁,如运行时用runtime.GOMAXPROCS把P的数量从32降到16时,剩余16个会被销毁,它们原来的G会先转到调度器
可运行的G队列
和自由G列表
(4)每个P中有可运行的G队列
(如图中最下面的那行G)和自由G列表
(图中未画出来),当G的代码执行完后,该G不会被销毁,而是被放到P的自由G列表
或调度器的自由G列表
。如果程序新建了Go协程,调度器会在自由G列表中取一个G,然后把Go协程的函数赋值到G中(如果自由G列表为空,就创建一个G);
可见Golang调度器在调度时很大程度复用了M,P,G
(5)在Go程序初始化后,调度器首先进行一轮调度,此时用M去搜索可运行的G。其中我们的main函数也是一个G,找到可运行的G后就执行它;
至于怎么找可运行的G呢?答案是到处找,想尽办法找(这里只列出一部分地方)。
- 从
本地P的可运行的G队列
找- 从
调度器的可运行的G队列
找- 从
其他P的可运行的G队列
找
(6)P的可运行G队列
最大只能存放长度为256的G,当队列满后,调度器会把一半的G转到调度器的可运行G队列
。
系统监控
上面大概描述了关于goroutine调度的流程。现在还存在一个问题,那就是当Go协程很多(并发量大)时候,显然G是不能一直执行下去的,因为也需要把执行机会留给其他的G。此时Golang运行时的系统监控就起作用了。
一般情况,当G运行时间超过10ms后,该G就会被系统告知需要停止了,让其他G运行。(这里情况比较复杂,并不能确保每个G都能被公平执行)
以下特殊情况该G不需要停止
- P的可运行G队列为空(没有其他G可运行)
- 有空闲的M在寻找可运行的G(没有其他G可运行)
- 空闲的P(还有P闲着)
总结
Golang以两级线程实现模型,自己实现goruntine和调度器,优势在于并行和非常低的资源使用。
主要体现:
- 内存消耗方面(每个Go协程占的内存远小于线程占的内存)
- 切换(调度)开销方面
- 线程切换涉及模式切换(从用户态切换到内核态)
此外,Go协程执行任务完成的顺序并不都是按我们预期的那样(程序不加以控制的情况下),特别在一些耗时较长的任务中。且每个Go协程执行的时间也不是绝对公平的。
如有错误地方,还请狂喷!
转载于:https://www.cnblogs.com/FireworksEasyCool/p/11508806.html
弄懂goroutine调度原理相关推荐
- 5分钟弄懂语音识别技术原理
5分钟弄懂语音识别技术原理 首先,我们知道声音实际上是一种波.常见的mp3.wmv等格式都是压缩格式,必须转成非压缩的纯波形文件来处理,比如Windows PCM文件,也就是俗称的wav文件.wav文 ...
- Golang 中的 Goroutine 调度原理与 Chanel 通信
简介 在 Go 中,每一个并发的活动称为一个 Goroutine 或者 协程.当一个程序启动时,只有一个 Goroutine 来调用 main 函数,称之为 主Goroutine.新的 Gorou ...
- go语言之行--golang核武器goroutine调度原理、channel详解
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
- 三幅图弄懂EventBus核心原理
前言 好多分析EventBus的文章,喜欢上来就贴源码,我看了好多次总是迷迷糊糊的,这次花时间彻底整理一下EventBus,发现EventBus核心其实就是三幅图,这三幅图涉及的是三个HashMap表 ...
- 20 张图彻底弄懂 HTTPS 的原理!
前言 近年来各大公司对信息安全传输越来越重视,也逐步把网站升级到 HTTPS 了,那么大家知道 HTTPS 的原理是怎样的吗,到底是它是如何确保信息安全传输的?网上挺多介绍 HTTPS,但我发现总是或 ...
- 18 张图彻底弄懂 HTTPS 的原理!
作者 | 码海 责编 | 张文 头图 | CSDN 下载自东方 IC 来源 | 码海(ID:seaofcode) 近年来各大公司对信息安全传输越来越重视,也逐步把网站升级成 HTTPS 了.那么,大 ...
- 一篇文章带你飞,轻松弄懂 CDN 技术原理
概述 Internet的高速发展,给人们的工作和生活带来了极大的便利,对Internet的服务品质和访问速度要求越来越高,虽然带宽不断增加,用户数量也在不断增加,受Web服务器的负荷和传输距离等因数的 ...
- 性能优化:弄懂goolg glog原理,提升程序性能
" 当弄清一个库的原理时,发现只需要一行环境变量,竟能让程序提升20倍以上性能,瞬间解决应用层瓶颈." 01 - Google glog使用 Google glog是一个实现应用程 ...
- 技术干货 | 一文弄懂差分隐私原理!
随着互联网的迅猛发展,网络早已融进人们日常生活的方方面面,我们的个人隐私在互联网时代几乎已经不是秘密.在数据时代,如何保护自己的隐私呢?差分隐私又是什么?小编用一篇文章带领大家了解什么是差分隐私,背后 ...
最新文章
- python皮同_Python OpenCV 图像的双线性插值算法,全网最细致的算法说明_橡皮擦,一个逗趣的互联网高级网虫-CSDN博客...
- Python为图像添加水印(add watermark to an image)
- idea springboot配置外置tomcat好处
- @propertysource 读不到properties_在加拿大读了6年还是大学一年级,会被赶出校吗?...
- 线程中这么调用类_「手撕面试官」谈谈你对JDK中Executor的理解?
- .NET平台常用的开发组件
- BugKuCTF 加密 简单加密
- python画图中grid等于true_Python3.0科学计算学习之绘图(二)
- vision画流程图的软件_产品流程图的定义,作用和画法
- LeetCode 671. 二叉树中第二小的节点
- shell 分割字符串_谈一谈Shell中的贪婪匹配和非贪婪匹配
- 笔记——常用网站总结
- java ocx调用_Javascript调用OCX控件
- 【JavaScript】去除空格
- Alexa工具栏研究
- PSP英文学习好助手 - 移动英语通PSP版
- 六轴机器人直角坐标系建立_六自由度机械手的坐标建立及运动学分析
- Win10环境VMware开WinXP虚拟机CPU占用100%
- 比较计算机动画与传统动画的异同,定格动画和传统动画有什么区别?基本一样吧?...
- 以太坊parity2.72节点客户端部署安装
热门文章
- check-lxdialog.sh: line 3: $'\r': command not found
- 把输入字符的小写转换成大写并输出
- Datawhale-零基础入门NLP-新闻文本分类Task01
- auto.js停止所有线程_Java多线程编程基础知识 概念介绍,以及线程状态
- oracle 删除补全日志组_Oracle 10g 添加、删除日志组
- eclipse的servlet默认不执行index_MySQL之索引及执行计划分析
- Mongodb 账户权限配置
- Chapter6_Vocoder
- TensorFlow 2.x GPU版在conda虚拟环境下安装步骤
- LeetCode 1256. 加密数字(bitset)