图解Go协程调度原理,小白都能理解
阅读本文仅需五分钟,golang协程调度原理,小白也能看懂,超实用。
什么是协程
对于进程、线程,都是有内核进行调度,有CPU时间片的概念,进行抢占式调度。协程,又称微线程,纤程。英文名Coroutine。协程的调用有点类似子程序,如程序A调用了子程序B,子程序B调用了子程序C,当子程序C结束了返回子程序B继续执行之后的逻辑,当子程序B运行结束了返回程序A,直到程序A运行结束。但是和子程序相比,协程有挂起的概念,协程可以挂起跳转执行其他协程,合适的时机再跳转回来。
线程调度原理
N:1模型,多个用户空间线程在1个内核空间线程上运行。优势是上下文切换非常快,因为这些线程都在内核态运行,但是无法利用多核系统的优点。
1:1模型,1个内核空间线程运行一个用户空间线程。这种充分利用了多核系统的优势但是上下文切换非常慢,因为每一次调度都会在用户态和内核态之间切换。POSIX线程模型(pthread)就是这么做的。
M:N模型,内核空间开启多个内核线程,一个内核空间线程对应多个用户空间线程。效率非常高,但是管理复杂。
goroutine调度原理
本质上goroutine就是协程,但是完全运行在用户态,借鉴了M:N模型。如下图
相比其他语言,golang采用了MPG模型管理协程,更加高效,但是管理非常复杂。
M:内核级线程
G:代表一个goroutine
P:Processor,处理器,用来管理和执行goroutine的。
G-M-P三者的关系与特点:
P的个数取决于设置的GOMAXPROCS,go新版本默认使用最大内核数,比如你有8核处理器,那么P的数量就是8
M的数量和P不一定匹配,可以设置很多M,M和P绑定后才可运行,多余的M处于休眠状态。
P包含一个LRQ(Local Run Queue)本地运行队列,这里面保存着P需要执行的协程G的队列
除了每个P自身保存的G的队列外,调度器还拥有一个全局的G队列GRQ(Global Run Queue),这个队列存储的是所有未分配的协程G。
假设我们的主机是单核的,那么协程运行图是这样:
红色部分表示挂起和休眠,黄色部分表示准备就绪等待运行,绿色部分表示正在运行。
主机是单核的所以只有一个处理器P,但是系统初始化了两个线程M0和M1,处理器P优先绑定了M0线程,M1进入休眠状态。
P的LRQ队列里有G1,G2,G3等待处理。P目前正在处理G0,全局等待队列GRQ里保存着G4,G5,表示这两个协程还未分配给P。
如果G0在短时间内处理完,P就会从LRQ中取出G1继续处理。并且将GRQ全局队列中的部分协程加入LRQ中。
如下图
假设现在G1处理速度很慢,系统就会让M0线程休眠,挂起协程G1,唤醒线程M1进行处理其他的协程。这里M1会将M0未处理的协程取走处理。
等到M1协程队列中所有协程处理完再次唤醒M0,或者M1处理某个协程时间较长被挂起,M0也会被唤醒。
上面的讨论是单核主机情况,如果是多核的,就会运行多个P和M,如下图
M0和M1分别运行在不同的内核中,M0处理G1,G2,G3,M1处理G4,G5,G6。
有人会问,当M0处理完所有的协程,而M1还未处理完,系统会如何做呢?
M0会取走M1的一半数量未处理的协程。
总结
golang协程设计非常优秀,一方面极大的利用了内核线程和处理器资源,另一方面每个处理器的LRQ队列的协程都处于用户态,这些协程的处理和挂起操作都是用户态的,协程切换开销非常小。相比其他语言的线程设计,更加轻量和高效。
以上就是golang协程调度原理。感谢关注我的公众号
图解Go协程调度原理,小白都能理解的更多相关文章
- go协程调度
目录 前言 1. 线程池的缺陷 2.Goroutine 调度器 3.调度策略 3.1 队列轮转 3.2 系统调用 3.3 工作量窃取 4.GOMAXPROCS设置对性能的影响 参考 前言 Gorout ...
- GO GMP协程调度实现原理 5w字长文史上最全
1 Runtime简介 Go语言是互联网时代的C,因为其语法简洁易学,对高并发拥有语言级别的亲和性.而且不同于虚拟机的方案.Go通过在编译时嵌入平台相关的系统指令可直接编译为对应平台的机器码,同时嵌入 ...
- Kotlin协程解析系列(上):协程调度与挂起
vivo 互联网客户端团队- Ruan Wen 本文是Kotlin协程解析系列文章的开篇,主要介绍Kotlin协程的创建.协程调度与协程挂起相关的内容 一.协程引入 Kotlin 中引入 Corout ...
- 协程的原理(Coroutine Theory)
原文链接:https://lewissbaker.github.io/2017/09/25/coroutine-theory This is the first of a series of post ...
- Openresty Lua协程调度机制
写在前面 OpenResty(后面简称:OR)是一个基于Nginx和Lua的高性能Web平台,它内部集成大量的Lua API以及第三方模块,可以利用它快速搭建支持高并发.极具动态性和扩展性的Web应用 ...
- Golang 协程调度
一.线程模型 N:1模型,N个用户空间线程在1个内核空间线程上运行.优势是上下文切换非常快但是无法利用多核系统的优点. 1:1模型,1个内核空间线程运行一个用户空间线程.这种充分利用了多核系统的优势但 ...
- 二、深入asyncio协程(任务对象,协程调用原理,协程并发)
由于才开始写博客,之前都是写笔记自己看,所以可能会存在表述不清,过于啰嗦等各种各样的问题,有什么疑问或者批评欢迎在评论区留言. 如果你初次接触协程,请先阅读上一篇文章初识asyncio协程对asy ...
- Unity 协程(Coroutine)原理与用法详解
前言: 协程在Unity中是一个很重要的概念,我们知道,在使用Unity进行游戏开发时,一般(注意是一般)不考虑多线程,那么如何处理一些在主任务之外的需求呢,Unity给我们提供了协程这种方式 为啥在 ...
- 写个百万级别full-stack小型协程库——原理介绍
其实说什么百万千万级别都是虚的,下面给出实现原理和测试结果,原理很简单,我就不上图了: 原理:为了简单明了,只支持单线程,每个协程共享一个4K的空间(你可以用堆,用匿名内存映射或者直接开个数组也都是可 ...
随机推荐
- ZOJ 4097 Rescue the Princess 边双缩点+LCA
给你一个图和三个点U,V,W 问你是否存在从U到V和从U到W的两条边不相交路径 先边双缩点 再每个连通分量搞LCA 最后LCA判 #include<bits/stdc++.h> usin ...
- tomcat 配置https协议
开发的人脸识别功能,在本地localhost是可以访问,换成IP地址不能访问,通过不了浏览器的安全协议, 要把http协议,转成https协议,才能正常访问 方案有二种 1.在项目springboot ...
- linux异步传输支持
基于libusbx-1.0.18-rc1,libusbx现已重新merage到libusb.1. 初始化使用libusb_init初始化libusb,如果是单设备通信,ctx参数可以传NULL,表示使 ...
- vmware 虚拟配置固定IP就无法联网 centos
centos7虚拟机初始运行时ip是动态随机分配的 通过修改etc/sysconfig/network-scripts/ifcfg-ens33文件的配置可以设置固定的ipTYPE=EthernetPR ...
- hdu3715 Go Deeper[二分+2-SAT]/poj2723 Get Luffy Out[二分+2-SAT]
这题转化一下题意就是给一堆形如$a_i + a_j \ne c\quad (a_i\in [0,1],c\in [0,2])$的限制,问从开头开始最多到哪条限制全是有解的. 那么,首先有可二分性,所以 ...
- Load store action in vulkan & ogles 的解决方案
metal的带宽之前的blog有讲 这篇主要是vulkan 和ogles的解决方案 https://www.khronos.org/registry/vulkan/specs/1.1-extensio ...
- Mysql-sql行转列
原始数据如下图所示:(商品的销售明细)date=业务日期:Item=商品名称:saleqty=销售数量 -- 建立测试数据(表)create table test (Date varchar(10), ...
- flutter 项目中打印原生安卓的log信息
因为项目的需要 在flutter 中调用安卓的方法 再用安卓的方法去调用c写的so包 方法 如果当前项目下面没有android stduio 自带的logcat 那就利用下面的方法 在安卓代码中引入 ...
- SQL Server的GO语句
https://www.cnblogs.com/cbattle/p/8784537.html go语句经常加在create.exec.drop等前面.
- NVMe Windows 支持情况
From NVMe 官网: Windows Driver – Microsoft Inbox • Closed source driver (Microsoft)• Inbox driver to W ...