目录

一、Go 语言的协程 goroutine

1. goroutine概念

2. goroutine特点

二、m:n调度技术

三、goroutine 调度器的实现

1. 被废弃的调度器

2.新调度器GPM设计思想

3.P和M的数量和创建

数量

创建

4.调度器的设计策略

线程复用

利用并行

抢占

全局 G 队列

5.GPM调度流程

6.调度器的生命周期


一、Go 语言的协程 goroutine

1. goroutine概念

goroutine 来自协程的概念,让一组可复用的函数运行在一组线程之上;
即使有协程阻塞,该线程的其他协程也可以被 runtime 调度,转移到其他可运行的线程上;

2. goroutine特点

占用内存更小(只占几 KB,可伸缩的,runtime会自动为goroutine分配更多内存);
调度更灵活 (runtime 调度);


二、m:n调度技术

m:n调度的技术,m个goroutine(G)调度到n个OS线程(M)上运行;

一对一和一对多的缺点;


三、goroutine 调度器的实现

1. 被废弃的调度器

2012年重新设计之前的调度器,只有GM;

特征:

1)M 想要执行、放回 G ,都必须访问全局 G 队列;

2)M 有多个,即多线程访问同一资源(即G队列)需要加锁进行保证互斥 / 同步。

老调度器有几个缺点:

1)激烈的锁竞争;

2)M 转移 G 会造成延迟和额外的系统负载;

比如当 G 中包含创建新协程的时候,M 创建了 G’;为了执行 G,需要把 G’交给 M’,也造成了很差的局部性,因为 G’和 G 是相关的,最好放在 M 上执行,而不是其他 M’;

3)系统调用 (CPU 在 M 之间的切换) 导致频繁的线程阻塞和取消阻塞操作增加了系统开销;

2.新调度器GPM设计思想

GPM是Go语言运行时层面(用户态)的实现,是go语言自己实现的一套调度系统,区别于操作系统调度OS线程(内核态)。

1)G:Goroutine,协程;

包含goroutine信息和与P的绑定信息;

2)P:Processor,调度器;

所有的 P 都在程序启动时创建,并保存在数组中,最多有 GOMAXPROCS(可配置) 个;

管理和调度一组goroutine队列,当自己的队列消费完了去全局队列里取,全局队列里消费完了会去其他P队列里取;

2)M:Machine,线程映射;

Go运行时(runtime)对操作系统内核线程的虚拟, M与内核线程一般是一一映射的关系;

线程想运行任务就得获取 P,从 P 的本地队列获取 G;

4)GQ:全局队列(Global Queue);

5)LQ:P 的本地队列;

存的数量有限,不超过 256 个;

满:新建 G’时,G’优先加入到 P 本地队列,如果队列已满,则把队列中前一半的 G和新创建的G移动到全局队列;

空:P 队列为空时,M 尝试从全局队列拿一批 G 【负载均衡,min(全局队列长度/P的数量  + 1, 全局队列长度/2)】放到 P 本地队列,或从其他 P 本地队列后一半放到自己 的P 本地队列;

协程和线程是通过P结合起来的(G - P -M), 线程想运行任务就得获取 P,从 P 的本地队列获取 G;

Goroutine 调度器和 OS 调度器是通过 M 结合起来的(goroutine调度器 - M - OS调度器);

3.P和M的数量和创建

数量

1)P 的数量:

由GOMAXPROCS决定,可配置;

这意味着在程序执行的任意时刻都只有 $GOMAXPROCS 个 goroutine 在同时运行;

2)M 的数量:

go 语言限制:go 程序启动时,会设置 M 的最大数量,默认 10000,但是内核很难支持这么多的线程数;

SetMaxThreads 函数,可设置 M 的最大数量;

一个 M 阻塞了,会创建新的 M;

3)M与P数量的关系:

M 与 P 的数量没有绝对关系,一个 M 阻塞,P 就会去创建或者切换另一个 M;

即使 P 的默认数量是 1,也有可能会创建很多个 M 出来;

创建

1)P 何时创建:

在确定了 P 的最大数量 n 后,运行时系统会根据这个数量创建 n 个 P。

2)M 何时创建:

没有足够的 M 来关联 P 并运行其中的可运行的 G时,会创建新的M;

比如所有的 M 此时都阻塞住了,而 P 中还有很多就绪任务,就会去寻找空闲的 M,而没有空闲的,就会去创建新的 M;

4.调度器的设计策略

线程复用

work stealing 机制

当本线程无可运行的 G 时,尝试从其他线程绑定的 P 偷取 G,而不是销毁线程。

hand off 机制

当本线程因为 G 进行系统调用阻塞时,线程释放绑定的 P,把 P 转移给其他空闲的线程执行。

利用并行

GOMAXPROCS 设置 P 的数量,最多有 GOMAXPROCS 个线程分布在多个 CPU 上同时运行。

抢占

在 coroutine 中要等待一个协程主动让出 CPU 才执行下一个协程;

在 Go 中,一个 goroutine 最多占用 CPU 10ms,防止其他 goroutine 被饿死;

全局 G 队列

在新的调度器中依然有全局 G 队列,但功能已经被弱化了;

当 M 执行 work stealing 从其他 P 偷不到 G 时,它可以从全局 G 队列获取 G;

5.GPM调度流程

从上图我们可以分析出几个结论:

1)我们通过 go func () 来创建一个 goroutine;

2)有两种存储 G 的队列,一个是局部调度器 P 的本地队列、一个是全局 G 队列;新创建的 G 会先保存在 P 的本地队列中,如果 P 的本地队列已经满了就会保存在全局的队列中;

3)G 只能运行在 M 中,一个 M 必须持有一个 P,M 与 P 是 1:1 的关系;M 会从 P 的本地队列弹出一个 G 来执行,如果 P 的本地队列为空,就会想其他的 MP 组合偷取一个可执行的 G;

4) 一个 M 调度 G 执行的过程是一个循环机制

5)当 M 执行某一个 G 时候如果发生了 syscall 或则其余阻塞操作,M 会阻塞;如果当前有一些 G 在执行,runtime 会把这个线程 M 从 P 中摘除 (detach);然后再创建一个新的操作系统的线程 (如果有空闲的线程可用就复用空闲线程) 来服务于这个 P;

6)当 M 系统调用结束时候,这个 G 会尝试获取一个空闲的 P 执行,并放入到这个 P 的本地队列;如果获取不到 P,那么这个线程 M 变成休眠状态, 加入到空闲线程中,然后这个 G 会被放入全局队列中。

6.调度器的生命周期

goroutine和GPM调度相关推荐

  1. go进阶(1) -深入浅出goroutine并发运行调度机制

    并发指的是同时进行多个任务的程序,Web处理请求,读写处理操作,I/O操作都可以充分利用并发增长处理速度,随着网络的普及,并发操作逐渐不可或缺 一.goroutine简述 在Golang中一个goro ...

  2. Go GPM 调度器介绍

    Go GPM 调度器介绍 1 简介 ​ 这几天在学习Go的GPM机制,于是就整理了一下收集的资料分享给大家,文章末尾有原文链接.主要介绍了Go在运行时调度器的基本实现逻辑和演变过程. ​ 2 什么是G ...

  3. 都说 Go 可以开启成千上万的 Goroutine,那调度器是怎么处理核上任务分配的?

    转载地址:https://mp.weixin.qq.com/s/_By9rjPgb8zqIpVrsJrToQ Illustration created for "A Journey With ...

  4. Go语言的GPM调度器是什么?

    博客主页:

  5. Go 开源说第十八期预告:基于 Reactor 模式开发网络服务——gnet

    点击蓝字 关注我们 写在前面 GoCN开源说是GoCN推出的一档分享Go开源好项目的直播栏目,通过开源说希望能够帮助到开源作者们实现以下目标: 第一是去推广他们的开源项目 第二说说背后的设计原理和理念 ...

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

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

  7. goroutine调度详解,以及进程、线程、协程区别

    转载地址:https://blog.csdn.net/Arlingtonroad/article/details/106952053?utm_medium=distribute.pc_relevant ...

  8. go 获取内核数_Go的GPM多线程调度

    现在前面:希望大家在做知识分享时,多验证自己内容的正确性.在学习GPM模型过程中,同一个概念看到了不同的解释.我查阅了一些资料选择了最可信的.由于我也没有阅读Go的调度源码,不能100%保证正确性,如 ...

  9. Goroutine并发调度模型深度解析之手撸一个协程池

    Goroutine & Scheduler Goroutine,Go语言基于并发(并行)编程给出的自家的解决方案.goroutine是什么?通常goroutine会被当做coroutine(协 ...

最新文章

  1. leetcode-142 环形链表II
  2. 《Elixir in Action》书评及作者问答录
  3. 探索7.x, 全面解析Activity启动框架 (1)
  4. 【翻译】卡通图解DNS,你的信息怎么被泄露的?
  5. Android input 子设备adb 调试命令
  6. ps cs3怎样能保存html,ps cs3用消失点清理杂物方法介绍
  7. 系统工程理论与实践投稿经验_钱学森的系统工程 | 如是读
  8. 时间序列-N-CNN-LSTM
  9. 前端框架 Angular 11.0.0 正式发布,已经放弃 IE 9 、10
  10. linux清除占用端口,Linux中解除端口占用的方法
  11. 3. Builder(建造者)
  12. Matlab中镜头畸变矫正
  13. Unity PlayerSetting设置
  14. 图像处理算法之图像暗角特效
  15. 10分钟从零搭建QQ机器人,实现自动回复、推送等功能
  16. 为什么中文不能用来编程呢?难道中文比英语差?看完长见识了
  17. 搞笑的各大银行的简称
  18. 高云FPGA实现驱动MIPI LCD屏
  19. css选择器优先级深入理解
  20. 1U和2U服务器应如何正确选择?各有什么优缺点?

热门文章

  1. 智能控制——模糊数学及控制
  2. 阿里妈妈 tanx ssp 推广位设置
  3. 硬件工程师必须牢记的十点总结
  4. 一粒云文控模块使用心得
  5. GitHub 标星 6
  6. Gradle构建项目深入浅出
  7. 全球最强截图软件 Snipaste
  8. 地震勘探原理c语言,《地震勘探原理》
  9. JDK1.8 api 中文文档下载
  10. 【GIS前沿】科学家绘制全球140多万个湖泊和水库的水下地形图