Golang调度模型GPM浅析
文章目录
调度前世今生
-
单进程执行,不存在调度,一起都是先来后到顺序执行;
-
效率低下
-
阻塞
-
-
多进程/多线程调度,提高cpu利用率;
-
效率一般,上下文切换开销
-
阻塞
-
-
协程提高cpu利用率,协程比线程更加轻量,占用更少的资源,进程/线程占用虚拟内存4MB,线程大概几KB。
GPM调度算法
GPM调度算法的基本原则如下:
-
时间片轮转:每个任务被分配一个固定的时间片(时间量),当时间片用完后,系统将切换到下一个任务。这种方式确保了任务之间的公平性,每个任务都有机会执行。
-
优先级调度:每个任务可以分配一个优先级,优先级较高的任务会被优先执行。如果多个任务具有相同的优先级,可以采用时间片轮转的方式来调度它们。
-
阻塞和唤醒:当一个任务需要等待某个事件发生时,它会被阻塞(暂停执行),直到事件发生后被唤醒(恢复执行)。这种方式可以确保系统资源的有效利用,避免任务空转。
-
调度策略:GPM调度算法通常采用先来先服务(FCFS)或轮转调度策略。先来先服务策略按照任务到达的顺序执行,轮转调度策略按照时间片轮转的方式执行。
GPM模型
-
G:表示执行的Goroutine
-
P:表示逻辑处理器Process,所有的P程序启动时创建,并保持到数组中,最多有GOMAXPROCS个。P的本地队列和全局队列一样,存放的是待运行的G,存放数量有限,大概不超过256个,G所创建的G’优先放入P的本地队列中,避免切换带来的开销。
-
M:表示线程,线程想运行任务就得获取P,从P的本地队列获取G,当P队列为空时,M也回尝试从全局队列获取一批放到P的本地队列,或者从其他P的本地队列重"偷"一半放到自己P的本地队列。
调度策略
-
复用线程,避免频繁创建、销毁线程。
偷取机制当本地队列无运行的G,会从其他P去偷取一部分G放入本地队列。偷取的动作一定是由P发起的,而非M,因为P的数量是固定的,如果一个M得不到一个P,那么这个M是没有执行的本地队列的,更谈不上向其他队列P偷取。
移交机制当本线程因为G进行系统调用阻塞时,线程会释放绑定的P,把P转移给其他空闲的线程执行。
-
利用并行
-
抢占
-
全局G队列
文章作者 dcq
上次更新 2023-09-23
许可协议 [Creative Commons Attribution-ShareAlike License](https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License)