社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
微信搜索【脑子进煎鱼了】关注这一只爆肝煎鱼。本文 GitHub github.com/eddycjy/blog 已收录,有我的系列文章、资料和开源 Go 图书。
大家好,我是煎鱼。
最近金三银四,是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。
今天的主角,是 Go 面试的万能题 GMP 模型的延伸题(疑问),那就是 ”GMP 模型,为什么要有 P?“
进一步推敲问题的背后,其实这个面试题本质是想问:”GMP 模型,为什么不是 G 和 M 直接绑定就完了,还要搞多一个 P 出来,那么麻烦,为的是什么,是要解决什么问题吗?“
这篇文章煎鱼就带你一同探索,GM、GMP 模型的变迁是因为什么原因。
在 Go1.1 之前 Go 的调度模型其实就是 GM 模型,也就是没有 P。
今天带大家一起回顾过去的设计。
我们了解一个东西的办法之一就是看源码,和煎鱼一起看看 Go1.0.1 的调度器源码的核心关键步骤:
static void
schedule(G *gp)
{
...
schedlock();
if(gp != nil) {
...
switch(gp->status){
case Grunnable:
case Gdead:
// Shouldn't have been running!
runtime·throw("bad gp->status in sched");
case Grunning:
gp->status = Grunnable;
gput(gp);
break;
}
gp = nextgandunlock();
gp->readyonstop = 0;
gp->status = Grunning;
m->curg = gp;
gp->m = m;
...
runtime·gogo(&gp->sched, 0);
}
schedlock
方法来获取全局锁。gput
方法来保存当前 Goroutine 的运行状态等信息,以便于后续的使用;nextgandunlock
方法来寻找下一个可运行 Goroutine,并且释放全局锁给其他调度使用。runtime·gogo
方法,将刚刚所获取到的下一个待执行的 Goroutine 运行起来。通过对 Go1.0.1 的调度器源码剖析,我们可以发现一个比较有趣的点。那就是调度器本身(schedule 方法),在正常流程下,是不会返回的,也就是不会结束主流程。
他会不断地运行调度流程,GoroutineA 完成了,就开始寻找 GoroutineB,寻找到 B 了,就把已经完成的 A 的调度权交给 B,让 GoroutineB 开始被调度,也就是运行。
当然了,也有被正在阻塞(Blocked)的 G。假设 G 正在做一些系统、网络调用,那么就会导致 G 停滞。这时候 M(系统线程)就会被会重新放内核队列中,等待新的一轮唤醒。
这么表面的看起来,GM 模型似乎牢不可破,毫无缺陷。但为什么要改呢?
在 2012 年时 Dmitry Vyukov 发表了文章《Scalable Go Scheduler Design Doc》,目前也依然成为各大研究 Go 调度器文章的主要对象,其在文章内讲述了整体的原因和考虑,下述内容将引用该文章。
当前(代指 Go1.0 的 GM 模型)的 Goroutine 调度器限制了用 Go 编写的并发程序的可扩展性,尤其是高吞吐量服务器和并行计算程序。
实现有如下的问题:
存在单一的全局 mutex(Sched.Lock)和集中状态管理:
Goroutine 传递的问题:
每个 M 都需要做内存缓存(M.mcache):
频繁的线程阻塞/解阻塞:
为了解决 GM 模型的以上诸多问题,在 Go1.1 时,Dmitry Vyukov 在 GM 模型的基础上,新增了一个 P(Processor)组件。并且实现了 Work Stealing 算法来解决一些新产生的问题。
GMP 模型,在上一篇文章《Go 群友提问:Goroutine 数量控制在多少合适,会影响 GC 和调度?》中已经讲解过了。
觉得不错的小伙伴可以关注一下,这里就不再复述了。
加了 P 之后会带来什么改变呢?我们再更显式的讲一下。
这时候就有小伙伴会疑惑了,如果是想实现本地队列、Work Stealing 算法,那为什么不直接在 M 上加呢,M 也照样可以实现类似的组件。为什么又再加多一个 P 组件?
结合 M(系统线程) 的定位来看,若这么做,有以下问题:
因此使用 M 是不合理的,那么引入新的组件 P,把本地队列关联到 P 上,就能很好的解决这个问题。
今天这篇文章结合了整个 Go 语言调度器的一些历史情况、原因分析以及解决方案说明。
”GMP 模型,为什么要有 P“ 这个问题就像是一道系统设计了解,因为现在很多人为了应对面试,会硬背 GMP 模型,或者是泡面式过了一遍。而理解其中真正背后的原因,才是我们要去学的要去理解。
知其然知其所以然,才可破局。
若有任何疑问欢迎评论区反馈和交流,最好的关系是互相成就,各位的点赞就是煎鱼创作的最大动力,感谢支持。
文章持续更新,可以微信搜【脑子进煎鱼了】阅读,回复【000】有我准备的一线大厂面试算法题解和资料;本文 GitHub github.com/eddycjy/blog 已收录,欢迎 Star 催更。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!