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协程执行的时间也不是绝对公平的。

如有错误地方,还请狂喷!

弄懂goroutine调度原理的更多相关文章

  1. go语言之行--golang核武器goroutine调度原理、channel详解

    一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...

  2. [GO语言的并发之道] Goroutine调度原理&Channel详解

    并发(并行),一直以来都是一个编程语言里的核心主题之一,也是被开发者关注最多的话题:Go语言作为一个出道以来就自带 『高并发』光环的富二代编程语言,它的并发(并行)编程肯定是值得开发者去探究的,而Go ...

  3. 一篇文章彻底弄懂Base64编码原理

    在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. Base64的由来 目前Base64已经成为网 ...

  4. 一篇文章彻底弄懂Base64编码原理(转载)

    在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. Base64的由来 目前Base64已经成为网 ...

  5. 知识扩展——(转)一篇文章彻底弄懂Base64编码原理

    在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. 一.Base64的由来 目前Base64已经成 ...

  6. 彻底弄懂jQuery事件原理二

    上一篇说到,我们在最外层API的on,off,tiggler,triggerHandler调用的是event方法的add,remove和tirgger方法,本篇就来介绍event辅助类 \ 先放个图, ...

  7. 彻底弄懂jQuery事件原理一

    jQuery为我们提供了一个非常丰富好用的事件API,相对于浏览器自身的事件接口,jQuery有以下特点: 1. 对浏览器进行了兼容性处理,用户使用不需要考虑浏览器兼容性问题 2. 事件数据是保持在内 ...

  8. 图解Go协程调度原理,小白都能理解

    阅读本文仅需五分钟,golang协程调度原理,小白也能看懂,超实用. 什么是协程 对于进程.线程,都是有内核进行调度,有CPU时间片的概念,进行抢占式调度.协程,又称微线程,纤程.英文名Corouti ...

  9. Golang/Go goroutine调度器原理/实现【原】

    Go语言在2016年再次拿下TIBOE年度编程语言称号,这充分证明了Go语言这几年在全世界范围内的受欢迎程度.如果要对世界范围内的gopher发起一次“你究竟喜欢Go的哪一点”的调查,我相信很多Gop ...

随机推荐

  1. 一文了解:Redis过期键删除策略

    Redis过期键删除策略 Redis中所有的键都可以设置过期策略,就像是所有的键都可以上"生死簿",上了生死簿的键到时间后阎王就会叉掉这个键.同一时间大量的键过期,阎王就会忙不过来 ...

  2. AutoCAD.NET中添加图形对象的基本步骤与实例演示

    https://blog.csdn.net/u011170962/article/details/37755201 要创建一个图形对象,需要遵循下面的步骤:1.得到创建对象的图形数据库:2.在内存中创 ...

  3. 源码分析--dubbo服务端暴露

    服务暴露的入口方法是 ServiceBean 的 onApplicationEvent.onApplicationEvent 是一个事件响应方法,该方法会在收到 Spring 上下文刷新事件后执行服务 ...

  4. 贪心算法-过河问题 pojo1700

    过桥问题: 黑夜,只有一只手电筒 A过桥需要1s B过桥需要3s C过桥需要5s D过桥需要8s E过桥需要12s 求最小过桥时间 贪心算法: 从最大的开始过去,最小的两个做为辅助. 假如左岸人数为2 ...

  5. Python爬虫,爬取腾讯漫画实战

    先上个爬取的结果图 最后的结果为每部漫画按章节保存 运行环境 IDE VS2019 Python3.7 先上代码,代码非常简短,包含空行也才50行,多亏了python强大的库 import os im ...

  6. BUPTOJj83

    83. A + B Problem 时间限制 1000 ms 内存限制 65536 KB 题目描述 Calculate the sum of two given integers A and B. 输 ...

  7. Vue+springboot管理系统

    About 此项目是vue+element-ui 快速开发的物资管理系统,后台用的java springBoot 所有数据都是从服务器实时获取的数据,具有登陆,注册,对数据进行管理,打印数据等功能 说 ...

  8. Numerical methods in enginering with python3 (1)

    <> (1) Numpy 库 Numpy中的矩阵函数 np.diagonal(A) 返回由A中的主对角元素组成的一维矩阵 np.diagonal(A,1) 返回由A中的第一副对角元素组成的 ...

  9. 【码上开心】Windows环境mysql数据库使用(一) 安装Mysql数据库

    [下载MySql] https://dev.mysql.com/downloads/mysql/ 如下图,选择版本,本教程仅演示ZIP压缩包下载配置. 2.[解压到指定目录] 3.[配置环境变量] 4 ...

  10. 【码上开心】Windows环境mysql数据库使用(二)skip-grant-tables 与用户名密码修改

    skip-grant-tables #跳过数据库权限验证 我们安装MySql 设置my.ini配置文件的时候,常常会在my.ini中添加 skip-grant-tables ,这时接数据库可以使用任意 ...