goroutine 调度原理

go routine 调度
一、goroutine 简介
goroutine 本质是协程,并行计算的核心。goroutine使用方式非常简单,只需要go关键字即可启动一个协程,并且它是处于异步方式执行,并不需要等他运行完成以后在执行以后的代码

二、 go routine 内部原理
概念介绍
在进行原理之前,先了解关键术语的概念

 

并发
一个cpu上面能同时执行多项任务,在短时间内,cpu来回切换任务执行(在短时间内执行a,然后又迅速的切换到b执行),宏观上是同时的,微观上是顺序执行的,看起来像是多个任务同时执行,这就是并发。

并行
系统有多个cpu每个cpu同一个时刻都运行任务,互不抢占自己所在的cpu的资源,同时进行,称为并行

进程
cpu在切换程序的时候,如果不保存上一个程序的状态,(我们所说的context–上下文),直接切换下一个程序,就会丢失上一个程序的一系列状态,于是引入了进程这个概念,用以划分好程序运行时所需要的资源。因此进程就是一个程序运行时侯所需要的基本资源单位(程序运行时的一个实体)。-----运行时保存有一系列资源的可执行程序实体

线程
cpu切换多个进程的时候,会花费不少时间,因为切换进程需要切换到内核态,而每次调度需要内核态都读取用户态的数据,进程一旦多起来,cpu调度会消耗一大堆资源,因此引入了线程的概念,线程本身几乎不占有资源,他们共享进程里面的资源,内核调度起来不会那么像进程切换那么消耗资源。

协程
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此,协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作执行者是用户自身程序,goroutine是协程。

调度模型简介
goroutine 能够拥有强大的并发是通过gpm调度模型实现。

M P G
go的调度器内部有四个重要的结构:M,P,S,Sched
img

M: M代表内核级的线程,一个M是一个线程,goroutine是跑在M之上的;M是一个很大的结构,里面维护小对象内存cache(mcache),当执行goroutine,随机数发生器等等非常多的信息。

G:代表一个goroutine ,他有自己的栈,instruction pointer 和其他信息(正在等待的channel等等),用于调度。

P:P全称是Processor处理器,他的主要用途是用来执行goroutine的,他维护了一个goroutine队列,里面存储了所有需要它来执行的goroutine

Sched :代表调度器,他维护有存储M和G的队列以及调度器的一些状态信息等。

调度实现

img
从上图中看,有两个物理线程M,每一个M都拥有一个处理器P,每一个都有一个正在运行的goroutine。

P的数量可以通过 GMAXPROCS()来设置,它其实也就代表了真正的并发度,即有多少个goroutine可以同时运行。

图中灰色的goroutine并没有运行,而是处于ready的就绪态,正在等待被调度。P维护着这个队列。(称之为runqueue)

go语言里,启动一个goroutine很容易:go func(){…}()就行,所以每有一个go语句被执行,runqueue就在队列末尾加入一个

在下一个调度点,goroutine 从runqueue中取出来(现在可以认为时随机取出来)并执行。

当一个os线程MO陷入阻塞时(如下图),P转而运行M1,图中M1可能正是被创建,或者从线程缓存取出。

当MO返回时候,他必须尝试取得一个P来运行goroutine,一般情况下,它会从其他的os线程那里拿一个P过来。

如果没有拿到的话,就把goroutine放在一个global runqueue里面,然后自己睡眠(放入线程缓存里面)。所有的P也会周期性的检查global runqueue 并运行其中的goroutine,否则global runqueue上的goroutine永远无法执行

另一种情况是p所分配的任务G很快就执行完了。(分配不均)这就导致了这个处理器p很忙,但是其他的p还有任务,此时如果global runqueue 没有任务G了,那么P不得不从其他的P那里拿来一些G来执行。一般来说,如果P从其他的P那里要拿任务的化,一般就 拿runqueue 的一半,确保每个os线程都能充分的使用。如下图

三、使用goroutine
基本使用
设置goroutine运行的cpu数量,最新版本的go已经默认设置了

num := runtime.NumCPU() //获取主机的逻辑cpu的个数
runtime.GOMAXPROCS(num) 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

anssummer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值