go的GMP调度

简介: 快速学习go的GMP调度

goroutine和线程的区别

从三个角度分析:内存消耗、创建和销毁、切换

内存消耗

  • 创建一个goroutine的栈消耗为2KB或4KB,在实际运行中,如果栈空间不够,会自动进行扩容。
  • 创建一个线程需要1MB

创建和销毁

  • goroutine是用户级的,是由go runtime控制创建和销毁的,代价非常小
  • 线程要和操作系统打交道,是内核级的,线程创建和销毁都会产生巨大的消耗。所以我们要是使用线程,一般都会使用线程池,尽量复用

切换

  • goroutine是用户级的,切换时只涉及到CPU上下文的切换,所谓的CPU上下文,就是一堆寄存器,里面保存了CPU运行任务需要的信息。所以,go协程切换非常简单,只需要把当前CPU寄存器状态保存起来,然后把切换进来的CPU寄存器加载上就行了。
  • 线程是内核级的,线程的切换涉及到用户空间和内存空间的切换,然后需要操作系统调度模块完成线程调度。谢忱刚切换时除了要保存和协程切换时的CPU上下文时,还要保存线程私有的栈和寄存器。也就是说,要保存的上下文比协程更多。
  • 一般协程切换只需要200ns,而协程需要1000 - 1500ns


M:N模型

当程序执行后,按需创建N个线程,之后创建M个协程依附在这N个线程上。这样做协程可以再用户态就完成切换,不会进入内核态。


G、M、P分别代表什么

  • G取的goroutine的首字母,保存了goroutine的一些状态信息和CPU的寄存器状态
  • M去machine首字母。就是工作进程,G只有调度到M上才能执行,M是真正工作的实体
  • P就是Processor首字母。为M的执行提供上下文,保存M执行G的一些资源,拥有调度Goroutine的能力

它们的关系是互相依赖的,M必须拥有P才能执行G中的代码,P中有一个包含多个G的队列,P可以调度G交给M执行


Goroutine调度策略

队列轮转

  • 每个p都维护一个G队列,在不考虑G进入系统调用或者IO的情况下,P会周期性的将G调度到M中执行。执行一段时间,将上下文保存,然后将这个G放到队列尾部,从队列重新取出一个G进行调度
  • 除了P维护的一个G队列之外,p还会周期性的查看队列中是否有G待运行并调度到M中执行。全局队列中的G,大部分是从系统调用中恢复的G,之所以p会周期性的查看全局队列,是为了防止全局队列中的G饿死

系统调用

  • G发生系统调用或者阻塞时,M会释放自己绑定的P。让某个空闲的M1去获取p,继续执行P队列中剩下的G。这个M1的来源可能是来自M的缓冲池,也可能是新建的
  • 当G的系统调用结束时,M会尝试获取一个P
  • 如果有空闲的P,将会尝试获取,继续执行这个G
  • 如果没有空闲的P,将Go放入全局队列中,等待被其他的P调用,然后这个M会进入缓冲池休眠

工作量窃取

  • 当线程绑定的P中的G全部执行完,就会尝试从全局队列获取G
  • 或者从其他的P中偷取P,一次偷一半


M0和g0

  • M0就是系统创建的第一个系统线程,也叫作主线程。是在进程启动时系统创建的,其他后续的M都是go Runtime自行创建的。负责的就是初始化和启动的工作
  • g0就是M第一个创建的goroutine,g0仅仅负责调度g,不指向任何函数。每一个M都只有一个g0


怎么控制M和P的数量

  • P的数量通过 runtime.GOMAXPROCS()控制
  • M的数量通过 runtime/debug包的,SetMaxThread()控制


相关文章
|
7月前
|
Go 调度 开发者
CSP模型与Goroutine调度的协同作用:构建高效并发的Go语言世界
【2月更文挑战第17天】在Go语言的并发编程中,CSP模型与Goroutine调度机制相互协同,共同构建了高效并发的运行环境。CSP模型通过通道(channel)实现了进程间的通信与同步,而Goroutine调度机制则确保了并发任务的合理调度与执行。本文将深入探讨CSP模型与Goroutine调度的协同作用,分析它们如何共同促进Go语言并发性能的提升。
|
4月前
|
Go 调度 C++
Go(1)——调度的本质
Go(1)——调度的本质
|
7月前
|
资源调度 监控 Go
Go中的GMP状态详解
【2月更文挑战第23天】
125 0
|
Go 调度
go基于信号的抢占式调度
go的调度器默认为抢占式调度。
218 0
|
缓存 Go 调度
Go并发调度进阶-循环调度,不是你理解的死循环
Go并发调度进阶-循环调度,不是你理解的死循环
|
监控 Java Go
Go并发调度进阶-GMP初始化,最难啃的有时候耐心看完还是很简单的
Go并发调度进阶-GMP初始化,最难啃的有时候耐心看完还是很简单的
|
存储 缓存 算法
Go并发调度进阶-GMP和调度器的主要结构,只有接触到底层你才更有底气
Go并发调度进阶-GMP和调度器的主要结构,只有接触到底层你才更有底气
Go并发调度-调度器设计理念从何而来?为何如此高效?
Go并发调度-调度器设计理念从何而来?为何如此高效?
|
缓存 Java Go
Go的GMP调度模型,看这篇就足够了
Go的GMP调度模型,看这篇就足够了
|
存储 监控 算法
golang 重要知识:golang 调度
Go 的调度机制相当于我们微服务里的基础组件。很多运行时操作都涉及到了调度的关联。本文会细聊调度概念,策略,以及它的机制。当然,也少不了最常提及的 GMP 模型。
391 0
golang 重要知识:golang 调度