调度器【Golang】

来自智得网
跳转至: 导航、​ 搜索

简介

一般情况下,线程/进程的调度是操作系统进行的,但是go语言的协程是语言层面实现的用户态线程,所以调度由go语言自己实现。

原理

调度时机

go语言的调度器分为三种调度类型,主动调度,被动调度,以及抢占调度。

主动调度

协程可以主动让出执行权力,协程在进行函数调用的时候,编辑器依赖提前插入的检查代码判断该协程是否要被抢占,但如果协程是长时间执行的CPU密集型运行,协程是无法被抢占的,1.14之后,go依靠操作系统的信号机制进行强制抢占。

被动调度

go的协程在执行休眠,channel通道阻塞,网络IO阻塞,GC的时候会被动让出自己执行的权力。和主动调度不同的是,被动调度不会把G放入GMP的全局运行队列,因为当前G的状态是Gwaiting,而不是可运行状态。

抢占调度

go语言初始化的时候就会启动一个特殊的线程执行系统监控,系统监控每隔10ms会检查是否有准备就绪的网络协程,将其放到全局运行队列,同时还会判断当前协程是否执行时间过程过长,或者处于系统调用,如果是则会抢占当前的协程。

调度机制

Golang语言的调度机制称为GMP,GMP分为三种角色:

  • G:Groutine协程,拥有运行函数的指针、栈、上下文(指的是sp、bp、pc等寄存器上下文以及垃圾回收的标记上下文),在整个程序运行过程中可以有无数个,代表一个用户级代码执行流(用户轻量级线程);
  • P:Processor,调度逻辑处理器,同样也是Go中代表资源的分配主体(内存资源、协程队列等),默认为机器核数,可以通过GOMAXPROCS环境变量调整
  • M:Machine,代表实际工作的执行者,对应到操作系统级别的线程;M的数量会比P多,但不会太多,最大为1w个。

调度执行

Go 的标准库提供了监测应用程序的线程sysmon,即系统监视器 (system monitor)。GMP 模型中,sysmon 协程未链接任何 P,不属于调度器管理的范畴,sysmon 协程在运行期间一直处于可执行状态。