GPM的几个关键点
-
文章参考:https://www.jianshu.com/p/fa696563c38a
-
刘丹冰大佬的github总结:https://github.com/aceld/golang
理解
- 名称
- G:go routine 协程
- 有些地方说跟协程还不完全一样,但大概可以这么理解。
- P:Processor 调度器
- M:内核线程
- G:go routine 协程
- 绑定关系
- P和M在同一时刻
一一对应
,如果发生解绑,P会再对应一个别的M。 - G总是要放在一个M上才能运行,实际上是多个G在不同时刻复用M。
- P和M在同一时刻
- M怎么取到G
- 首先,从对应P的
本地G队列
拿(为了局部性) - 拿不到就从
全局G队列
获取到本地G队列
,不会拿很多,防止别的P/M拿不到 - 全局也没有的话就从
别的
正常P/M本地G队列
里面偷一点 - 实在没有就只能自旋了,有一个
空闲P队列
维护了空闲的P/M组合- 因为自旋费CPU,所以P有上限,由
GOMAXPROCS
控制,一般我觉得搞成线程数合适
- 因为自旋费CPU,所以P有上限,由
- 首先,从对应P的
- G产生的G放哪里
- 首先尝试放
本地G队列
(局部性) - 要是本地满了,就把
本地G队列
的一半G挪到全局G队列
(负载均衡) - 继续放,就能放在
本地G队列
了
- 首先尝试放
- G运行的时候阻塞怎么办
- 直接把G/M组合和P解绑
- P获取新的M(从
休眠M队列
里面拿,或者重新创建),跑新的G - 阻塞的G等到它阻塞结束,自己去找一个P(原先的P或者
空闲P队列
)- 找不到P就只能
解散
了,M自己去休眠,G放到全局等分配
- 找不到P就只能