golang的goroutine调度模型

进程:一个在内存中运行的程序

线程:进程中的一个控制单元,一个进程至少由一个线程,也可以由多个线程,主要由CPU进行调度。

形象理解:进程就是一个生产某样产品的工厂,线程就是工厂里面的生产车间。

golang的goroutine是一个轻量化的线程。一个go主线程就可以轻轻松松起成千上万个goroutine。主要特点:

  1. 有独立的占空间
  2. 共享程序的堆空间
  3. 调度由用户掌控

golang的gouroutine的调度模型为MPG模型

  • M:操作系统的主线程(物理线程,由CPU调度)
  • P:协程执行所需要的上下文
  • 协程

golang起一个goroutine很简单,只需要一个关键字go就可以轻松起一个goroutine

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYdaqagH-1663260806647)(C:\Users\fei\AppData\Roaming\Typora\typora-user-images\image-20220916001557361.png)]

  1. golang起的goroutine会放在一个全局队列中,全局队列遵循先进先出的原则
  2. M(线程)则从全局队列中获取goroutine,每个M(线程)获取goroutine的时候,会进行加锁操作,获取goroutine完成后再释放锁,以此保证安全
  3. P(上下文)负责管理一个本地队列,M(线程)一次性从全局队列中获取n个goroutine,并将goroutine放到自己的一个本地队列中,n=全局队列goroutine总数/GOMAXPROCS+1
  4. M(线程)根据队列先进先出的原则,先执行本地队列中的goroutine,本地队列的goroutine执行完了,再到全局队列取,全局队列取完了,视情况到其他M(线程)的本地队列取。

为了保证资源调配公平,M(线程)执行G(协程)的时间超过10ms,将中断G(协程)并将这个G(协程)重新放入全局队列的队尾。

还有一种情况:goroutine下又创建goroutine

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JX7KxPEa-1663260806649)(C:\Users\fei\AppData\Roaming\Typora\typora-user-images\image-20220916004209507.png)]

  1. 将goroutine下创建的goroutine放到本地队列的队首位置,下一个优先执行
  2. 为了防止无限套娃创建goroutine,占住M(线程资源),G(协程)下创建的所有goroutine公用一个10ms时间片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDa2VF01-1663260806650)(C:\Users\fei\AppData\Roaming\Typora\typora-user-images\image-20220916004447135.png)]

图片转存中…(img-uDa2VF01-1663260806650)]

说明例子:假如父goroutine执行了3ms后创建了子goroutine,那子goroutine最多只能执行7ms,超过10ms,整个G(协程)就会被中断,被扔回全局队列。