一:什么是调度

平常我们在生活中会有哪些调度的例子呢?比如十字路口的红绿灯,它就是一种调度系统。在交通十字路口,每个路口上多多少少有一些车辆,为了限制这些车辆不随意行驶,就建起了红绿灯调度系统。红绿灯可以有序的调度这些车辆行驶,使这些车辆快速的通过路口。

那为什么需要红绿灯来进行调度呢?

1:使车辆有序的行驶不至于相撞

2:使车辆能快速的通过路口

上面的红绿灯系统有哪些元素呢?1. 红绿灯系统-负责调度车辆  2. 车辆  3. 十字路口

由此我们可以看出一个调度系统基本元素有2个:1. 调度系统 2. 被调度的东西 3. 应用的资源
因为资源(十字路口)是有限的,每个方向只有一条路可供车辆行驶,而车辆在每个路口又是很多的,这是不是就形成了资源和使用者之间的矛盾了,为了解决这个矛盾,红绿灯调度系统应运而生。
如果我有多层路口,比如高架桥,多了一层,那走上面的车辆是不是就不需要等红绿灯了。这应该是调度系统在生活中的启示。

所以我们可以说调度系统是协调被调度的物件合理的使用资源。

也可以回顾下以前学习Linux系统中的调度,被调度的物件是线程或者进程,资源是cpu,为了协调有限的cpu资源在多个线程(进程)中合理公平使用,就有了调度器。

那golang中的调度呢?

跟上面的红绿灯调度有一些相似点。

golang的调度是为了多个协程能合理的利用线程。这里的协程(goroutine)相当于车辆了,线程相当于十字路口(也许不恰当)。

go在运行时,会运行很多协程goroutine,也就是我们常说的并发,go为了能使这些协程有序的快速的在线程上执行,就需要进行调度了。

还有,go为了方便的控制goroutine,比如把当前线程中的goroutine移交到其他线程继续执行,从而避免应线程阻塞影响协程的运行。

还有,go中引入了GC,在执行GC的时候,要求所有goroutine停止,自己实现调度器,就可以方便实现这个功能了。

相对于操作系统的线程来说,goroutine更加的轻量,占用的内存更小,上下文进行切换时换入换出的数据也更少。

二:goroutine简介

我们说Go是语言级别的并发语言。为什么是语言级别?那不还有系统级别,对,操作系统级别就实现了多线程,多进程这种并发。

有2个支持高并发的模型:CSPActor(erlang)。Go 选择了CSP,Go为了提供更容易的并发使用方法,提供了2个重要的概念 goroutinechannel

goroutine来自协程的概念,让一组可复用的函数运行在一组线程之上,即使有协程阻塞,该线程的其他协程也可以被runtime调度,转移到其他可运行的线程上。最关键的是,程序员看不到这些底层的细节,这就降低了编程的难度,提供了更容易的并发。

goroutine非常的轻量,只占几KB,并且这几KB足够goroutine运行完。所以我们运行成千上万的goroutine成为可能,因为不会占用太多的内存资源。

channel为goroutine之间提供了通信功能。

不要通过共享内存来通信,而应该通过通信来共享内存

三:go调度模型GMP

go的调度模型,一开始并不是GPM模型,而是经过了一个发展过程。
老的调度模型只有G和M,没有P。为什么只有GM呢?因为这是一个简单的模型,最开始开发时一定容易实现。

M:代表OS线程,它是运行goroutine的

G:就是goroutine

它还有一个重要的数据结构:全局队列global runqueue。
为什么会有队列?它有什么作用?
全局队列是用来存放goroutine(G)的。启动那么多goroutine,总要一个地方把G存起来以便M来调用。

多个M会从这个全局队列里获取G来进行运行。


GM模型如下图:

M要执行G,或者把G放回去,都要访问全局队列,而且M还是多个,所以必须对全局队列加锁保证互斥。
这必然导致多个M对锁的竞争。这也是老调度器的一个缺点。

其实老调度器有4个缺点:详见Scalable Go Scheduler Design Doc

  1. 创建、销毁、调度G都需要每个M获取锁,这就形成了激烈的锁竞争
  2. M转移G会造成延迟和额外的系统开销。
  3. M中的mcache是用来存放小对象的,mcache和栈都和M关联造成了大量的内存开销和差的局部性
  4. 系统调用导致频繁的线程阻塞和取消阻塞操作增加了系统开销。

所以Go语言在2012年重新设计了调度器方案(Scalable Go Scheduler Design Doc设计方案)。

在GO1.1中新调度器引入了:

  • P(processor),它包含了运行goroutine的资源。如果线程M想运行G(goroutine),比如先获取P,P中还包含了可运行的G队列。
  • work stealing:当M绑定的P没有可运行的G时,它可以从其他运行的M那里偷取G来运行。这个的作用就是避免M因为没有可运行的G时产生饥饿的问题。

    work stealing算法地址

新调度器就是一个GPM模型了:

  • G:goroutine,用户级别的线程(协程)。我们在程序里用go关键字创建的一个协程。
  • P:processor,相当于一个处理器,它包含了goroutine运行的资源,M必须和一个P关联才能运行G。P还包含自己的本地队列(local runqueue)来保存G。为什么要搞一个本地队列?这样就可以避免竞争锁了。
  • M:工作线程,代表机器(machine)。这个线程是OS来处理的,OS负责把线程放到cpu上去运行。

当然新调度器也有一个很重要的数据结构:全局运行队列 global runqueue。

题外话:引入P,解决了老调度器的一些问题,但是同时也增加了调度器的复杂度。这个是必然的,引入新东西必然会增加系统的复杂度。就看能不能很好的解决问题,权衡利弊。

GPM模型如下图:

(图来自:https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html

GRQ:全局队列 global runqueue

LRQ:P的本地队列 local runqueue

G:goroutine协程

M:OS的线程,用来绑定P,运行G,真正执行指令的人。

P:processor,goroutine运行时所需要的资源。P的数量可以用runtime.GOMAXPROCS()来控制。

每个P会分配一个LRQ(本地队列)去处理P的上下文要执行的Goroutines 。这些Goroutines会在绑定到P的M上进行上下文的切换。GRQ(全局队列)会处理还没有分配到P上的Goroutines 。

新的调度器中有全局队列,但功能已经被弱化了,当M执行work stealing从其他P偷不到G时,它可以从全局队列获取G。

抢占式调度

G-P-M模型的实现算是Go scheduler的一大进步,但Scheduler还有一个很头疼的问题,那就是不支持抢占式调度。

为什么要抢占式调度?

因为一旦某个G出现死循环或者永久循环的代码逻辑,那么G将永久占用分配给他的P和M,位于同一个P中的其他G将得不到调度,出现饿死的情况。还有一种情况,当只有一个P(GOMAXPROCS=1),

整个Go程序中的其他G都将饿死。于是Dmitry Vyukov提出了《Go Preemptive Scheduler Design》

并在Go 1.2中实现了“抢占式”调度

一些说明:

1、M绑定P,才可以不断的去运行G,如果M没有可运行的G,也可以抢占式调度(依靠sysmon)

2、从上图可以看出,每个P都有自己的本地队列,也有一个全局队列

3、M,P,G三者的数量,M默认10000,可以设置,通过SetMaxThreds修改,P默认是CPU的核数,可以设置,通过GOMAXPROCS修改,

G没有数量限制,可以创建成百上万个,甚至百万。

4、M可以与P解绑,也可以休眠

新的调度器有没有缺点?有

1、 runqueue只是一个没有优先级的队列,所以会按照先进先出的顺序来运行Goroutine。

2、调度goroutine时公平性没有很好的保证:已经提议进行修改。

3、 runqueue没有利用缓存,使用缓存[栈而不是队列]可以加速Goroutine的访问。

四:参考:

深入理解Go语言(03):scheduler调度器 - 基本介绍的更多相关文章

  1. quartz2.3.0(十二)通过RMI协议向Scheduler调度器远程添加job任务

    此代码示例通过RMI协议向Scheduler调度器远程添加job任务. 代码文件包括:job任务类(SimpleJob.java).RMI服务端server类(RemoteServerExample. ...

  2. scrapy 源码解析 (四):启动流程源码分析(四) Scheduler调度器

    Scheduler调度器 对ExecutionEngine执行引擎篇出现的Scheduler进行展开.Scheduler用于控制Request对象的存储和获取,并提供了过滤重复Request的功能. ...

  3. IO调度器原理介绍

    IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法.存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间.然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平 ...

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

    我是平也,这有一个专注Gopher技术成长的开源项目「go home」 导读 相信很多人都听说过Go语言天然支持高并发,原因是内部有协程(goroutine)加持,可以在一个进程中启动成千上万个协程. ...

  5. Yarn 调度器Scheduler详解

    理想情况下,我们应用对Yarn资源的请求应该立刻得到满足,但现实情况资源往往是有限的,特别是在一个很繁忙的集群,一个应用资源的请求经常需要等待一段时间才能的到相应的资源.在Yarn中,负责给应用分配资 ...

  6. Yarn 组件的指挥部 – 调度器Scheduler

    linux基础 为hadoop集群的搭建扫清了障碍,也为内存的管理,文件系统的管理扫清了障碍 接着到Hadoop的阶段,首先做集群的安装,深入到使用这两个核心的组件,分布式文件系统HDFS,解决大量数 ...

  7. hadoop之 Yarn 调度器Scheduler详解

    概述 集群资源是非常有限的,在多用户.多任务环境下,需要有一个协调者,来保证在有限资源或业务约束下有序调度任务,YARN资源调度器就是这个协调者. YARN调度器有多种实现,自带的调度器为Capaci ...

  8. 调度器简介,以及Linux的调度策略

    进程是操作系统虚拟出来的概念,用来组织计算机中的任务.但随着进程被赋予越来越多的任务,进程好像有了真实的生命,它从诞生就随着CPU时间执行,直到最终消失.不过,进程的生命都得到了操作系统内核的关照.就 ...

  9. 调度器简介,以及Linux的调度策略(转)

    进程是操作系统虚拟出来的概念,用来组织计算机中的任务.但随着进程被赋予越来越多的任务,进程好像有了真实的生命,它从诞生就随着CPU时间执行,直到最终消失.不过,进程的生命都得到了操作系统内核的关照.就 ...

  10. Linux内核——进程管理之CFS调度器(基于版本4.x)

    <奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...

随机推荐

  1. [转帖]Linux中查找大文件两种姿势

    https://rumenz.com/rumenbiji/linux-find-du-max-file.html 使用find命令查找大文件 find命令是Linux系统管理员工具库中最强大的工具之一 ...

  2. [转帖]Jmeter学习笔记(六)——使用badboy录制脚本

    https://www.cnblogs.com/pachongshangdexuebi/p/11506274.html 1.下载安装 可以去badboy官网下载地址:http://www.badboy ...

  3. 【转帖】ethool工具之TSO、UFO、GSO、LRO、GRO和RSS介绍

    ethtool -k < 网络接口>, ethtool --show-offload < 网络接口>, 或者可以看到很多网络接口的offload特性,例如: $ sudo et ...

  4. [转帖]服务注册与发现:Nacos Discovery

    目录 一.概述 二.Nacos discovery--服务的注册与发现 1. 版本关系 2. 下载安装 (1)下载 (2)启动 (3)浏览器访问 三.Nacos服务注册与发现实战 1. 构建Sprin ...

  5. [知乎]2019-nCov的致死率问题

    https://www.zhihu.com/question/369630554/answer/998649507 知乎 dr.李的文章 跟自己一开始的理解很相似.. 个人也认为死亡率会高于2% 武汉 ...

  6. 下载 ingres-nginx

    https://quay.io/repository/kubernetes-ingress-controller/nginx-ingress-controller-arm64?tag=latest&a ...

  7. 为什么Kubernetes和容器与机器学习密不可分?

    原文出自infosecurity 作者:Rebecca James 京东云开发者社区编译 当前,数字化转型的热潮在IT领域发展的如火如荼,越来越多的企业投身其中,机器学习和人工智能等现代技术的融合在公 ...

  8. echarts饼图的配置 封装组件的注意点

    1==>tooltip 类似饰hover效果提示框组件.光标放上去会触发 2==>formatter // 饼图 {a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比 ...

  9. linux如何配置ssh密钥登录

    为什么要用ssh密钥登录 购买的服务器设置密码很容易被暴力破解,用密钥登录安全很多.root用户新建的用户也要用密钥登录更安全,如果一直su - 用户名登录 不方便 用xftp等服务上传文件到用户使用 ...

  10. ABP vNext系列文章10---分布式事务集成netcore.Cap

    最近项目中要用到分布式事务功能,调研了DTM和Cap,最终确定用Cap来实现,Cap支持最终一致性,项目中采用MQ作为消息中间件,数据库用的mysql,集成步骤如下: 1.在需要发布消息的服务中引入如 ...