文章继续更新,能够微信搜一搜「golang 小白成长记」第一工夫浏览,回复【教程】获 golang 收费视频教程。本文曾经收录在 GitHub https://github.com/xiaobaiTec… , 有大厂面试残缺考点和成长路线,欢送 Star。
GM 模型是什么
在 Go 1.1
版本之前,其实用的就是 GM
模型。
- G,协程。通常在代码里用
go
关键字执行一个办法,那么就等于起了一个G
。 - M,内核 线程,操作系统内核其实看不见
G
和P
,只晓得本人在执行一个线程。G
和P
都是在 用户层 上的实现。
除了 G
和M
以外,还有一个 全局协程队列 ,这个全局队列里放的是多个处于 可运行状态 的G
。M
如果想要获取 G
,就须要拜访一个 全局队列 。同时,内核线程M
是能够同时存在多个的,因而拜访时还须要思考 并发 平安问题。因而这个全局队列有一把 全局的大锁,每次拜访都须要去获取这把大锁。
并发量小的时候还好,当并发量大了,这把大锁,就成为了 性能瓶颈。
GMP 模型是什么
基于 没有什么是加一个中间层不能解决的 思路,golang
在原有的 GM
模型的根底上退出了一个调度器 P
,能够简略了解为是在G
和M
两头加了个中间层。
于是就有了当初的 GMP
模型里。
P
的退出,还带来了一个 本地协程队列 ,跟后面提到的 全局队列 相似,也是用于寄存G
,想要获取期待运行的G
,会 优先 从本地队列里拿,拜访本地队列无需加锁。而全局协程队列仍然是存在的,然而性能被弱化,不到 万不得已 是不会去全局队列里拿G
的。GM
模型里 M 想要运行G
,间接去全局队列里拿就行了;GMP
模型里,M
想要运行G
,就得先获取P
,而后从P
的本地队列获取G
。
- 新建
G
时,新G
会优先退出到P
的本地队列;如果本地队列满了,则会把本地队列中一半的G
挪动到全局队列。 P
的本地队列为空时,就从全局队列里去取。
- 如果全局队列为空时,
M
会从其余P
的本地队列 偷(stealing)一半 G 放到本人P
的本地队列。
M
运行G
,G
执行之后,M
会从P
获取下一个G
,一直反复上来。
为什么 P 的逻辑不间接加在 M 上
次要还是因为 M
其实是 内核 线程,内核只晓得本人在跑线程,而 golang
的运行时(包含调度,垃圾回收等)其实都是 用户空间 里的逻辑。操作系统内核哪里还晓得,也不须要晓得用户空间的 golang 利用原来还有那么多花花肠子。这所有逻辑交给应用层本人去做就好,毕竟改内核线程的逻辑也不适合啊。
如果文章对你有帮忙,看下文章底部右下角,做点正能量的事件(点两下 )反对一下。( 疯狂暗示,托付托付,这对我真的很重要!)
我是小白,咱们下期见。
参考资料
[1]《Golang 调度器 GMP 原理与调度全剖析》——Aceld :https://learnku.com/articles/…
[2]《GMP 模型为什么要有 P》——煎鱼 :https://mp.weixin.qq.com/s/an…
[3]《深度解密 Go 语言之 Scheduler》——qcrao :https://qcrao.com/2019/09/02/…
文章举荐:
- i/o timeout,心愿你不要踩到这个 net/http 包的坑
- 妙啊! 程序猿的第一本互联网黑话指南
- 程序员防猝死指南
- 我感觉,我可能要拿图灵奖了。。。
- 给大家争脸了,用了三年 golang,我还是没答对这道内存透露题
- 硬核!漫画图解 HTTP 知识点 + 面试题
- TCP 粘包 数据包:我只是犯了每个数据包都会犯的错 | 硬核图解
- 硬核图解!30 张图带你搞懂!路由器,集线器,交换机,网桥,光猫有啥区别?
别说了,关注公众号:【golang 小白成长记】,一起在常识的陆地里呛水吧
关注公众号:【golang 小白成长记】