----------1、调度器由来与分析
早期单进程OS:顺序执行的lowB
1、一个任务一个任务执行
2、进程阻塞带来CPU浪费

多线程、多进程调度
CPU调度器:时间片切换到ABC进程。
解决了阻塞问题。
新的问题:
宏观并发,线程cpu切换成本高,要保存当前状态,等系统调用,上下文切换、内存拷贝复制等。
1、线程/进程数量越多,成本越大,cou利用率低。
2、高内存,进程占用内存过大,虚拟内存4G,线程4MB。

将线程分为内核线程(系统调用层面)、用户线程(业务层面)
CPU本身只管理内核态线程

-------------------------golang早期调度器
用户线程=协程
内核线程=thread
N个协程-----------------协程调度器(论询)------------1个内核线程
1个协程-----------------协程调度器(论询)------------1个内核线程(老模式)
M个协程-----------------协程调度器(论询)------------N个内核线程
不同语言不同协程调度器。
goroutine优化:
几kb,大量创建
灵活调度、正常切换

问题最终:
回归到协程调度器的优化


----------2、调度器GMP模型的设计思想
---1、GMP模型简介
G=gorountine
P=processor 处理器
M=thread 内核态线程
上、中、下
执行、调度、资源

 


 

全局队列存储等待运行的goroutine

P=本地队列:就是每一个处理器厨存储将要执行的gorountine,一般不超过256。insert操作如果满就放入全局队列里。

P列表:最高并行就是个数=gomaxprocs个/环境变量GOMAXPROCS

---M列表:当前用户OS给GO程序分配内核线程数。

默认是10000,一般OS几乎达不到。

SetMaxThread函数设置

一个M阻塞,会创建一个新的M

M空闲就会收回

 

-----2、调度器设计策略

--1、复用线程

1、work stealing机制

P会steal别别的P队列

 

-----2、hand off机制

如果发现某个P队列阻塞操作,将该P移动到新的M3,M1继续执行,但是P里面其他G重新被启动了。

 

 

 

2、利用并行

----------限定P个数=CPU核数/2

 

3、抢占

G-----P-------M---CPU

每一个G最多10ms,新的G会抢占CPU

 

4、全局G队列

stealing 优先从其他P偷,如果没有从全局队列偷取,加解锁。

----------------3、使用go func方法执行的数据流

1、G加入P,如果P满了加入全局队列。stealing机制

2、P调用M去执行G。

3、G执行的过程中有read阻塞,新创建一个M接管该被阻塞的G所在的P。handoff机制

4、旧的M要么销毁要么加入休眠队列。

5、G寻找其他队列,或者全局队列。

核心操作是对阻塞后的,P给新的M,以及旧M销毁/休眠,还有G加入全局队列。

参考:
https://www.bilibili.com/video/BV19r4y1w7Nx?p=3&spm_id_from=pageDriver