Go语言协程调度器GPM模型

为了提高Go程序对于CPU的利用率。Go语言的设计者,设计了GPM模型,并且实现了一个高效的协程调度器。

协程Goroutine

从操作系统层面去看,一般可以把线程分为“用户态”和“内核态”。“用户态”可以理解为编程语言实现的线程,而“内核态”可以理解为操作系统实现的线程。“用户态”线程必须和“内核态”线程绑定,才能正常执行。
一个线程中的用户态和内核态

GPM模型

Go的Goroutine即为“用户态”线程的Go语言实现。而管理Goroutine和“内核态”线程绑定关系的管理器,被称为“协程调度器”。“协程调度器”的模型有三个组件组成:G(协程Goroutine)、M(线程Thread)、P(处理器Processor)。
GPM模型

  1. P的数量可以通过GOMAXPROCS环境变量设置,或者通过runtime.GOMAXPROC()函数设置。
  2. M的最大数量可以通过runtime/debug的SetMaxThreads()函数设置,当一个M阻塞时,会去创建一个新的M。

心中有个疑问,是否可以不需要P或者M?可当前这样的设计有更多的灵活性吧。

调度器的策略

调度器的作用,就是平衡任务和操作系统资源,而且必须是高效,高效,高效。

  1. 偷取,一个P从其他P的本地队列偷取G
  2. 移交,执行G发生阻塞,则会将当前关联的P移交给其他M执行
  3. 抢占,每个G占用CPU资源的时间固定,其他G能够抢占CPU资源
  4. 全局队列,针对P使用的本地队列,发生空载或者满载的时候,多了一层缓存机制
    有种类似消息队列,削峰填谷的作用

调度器生命周期

Goroutine初始化过程中M0和G0的作用

参考文献

  1. 《深入理解Go语言》-刘丹冰