首页 后端开发 Golang 再见 Go 面试官:GMP 模型,为什么要有 P?

再见 Go 面试官:GMP 模型,为什么要有 P?

Aug 08, 2023 pm 04:31 PM
gmp


今天的主角,是 Go 面试的万能题 GMP 模型的延伸题(疑问),那就是 ”GMP 模型,为什么要有 P?“

进一步推敲问题的背后,其实这个面试题本质是想问:”GMP 模型,为什么不是 G 和 M 直接绑定就完了,还要搞多一个 P 出来,那么麻烦,为的是什么,是要解决什么问题吗?“

这篇文章煎鱼就带你一同探索,GM、GMP 模型的变迁是因为什么原因。

GM 模型

在 Go1.1 之前 Go 的调度模型其实就是 GM 模型,也就是没有 P。

今天带大家一起回顾过去的设计。

解密 Go1.0 源码

我们了解一个东西的办法之一就是看源码,和煎鱼一起看看 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 方法来获取全局锁。schedlock 方法来获取全局锁。
  • 获取全局锁成功后,将当前 Goroutine 状态从 Running(正在被调度) 状态修改为 Runnable(可以被调度)状态。
  • 调用 gput 方法来保存当前 Goroutine 的运行状态等信息,以便于后续的使用。
  • 调用 nextgandunlock 方法来寻找下一个可运行 Goroutine,并且释放全局锁给其他调度使用。
  • 获取到下一个待运行的 Goroutine 后,将其运行状态修改为 Running。
  • 调用 runtime·gogo
获取全局锁成功后,将当前 Goroutine 状态从 Running(正在被调度) 状态修改为 Runnable(可以被调度)状态。

调用 gput 方法来保存当前 Goroutine 的运行状态等信息,以便于后续的使用。

调用 nextgandunlock 方法来寻找下一个可运行 Goroutine,并且释放全局锁给其他调度使用。
再见 Go 面试官:GMP 模型,为什么要有 P?
获取到下一个待运行的 Goroutine 后,将其运行状态修改为 Running。

调用 runtime·gogo 方法,将刚刚所获取到的下一个待执行的 Goroutine 运行起来,进入下一轮调度。

思考 GM 模型

通过对 Go1.0.1 的调度器源码剖析,我们可以发现一个比较有趣的点。那就是调度器本身(schedule 方法),在正常流程下,是不会返回的,也就是不会结束主流程。

🎜🎜🎜G-M模型简图🎜🎜🎜他会不断地运行调度流程,GoroutineA 完成了,就开始寻找 GoroutineB,寻找到 B 了,就把已经完成的 A 的调度权交给 B,让 GoroutineB 开始被调度,也就是运行。🎜🎜当然了,也有被正在阻塞(Blocked)的 G。假设 G 正在做一些系统、网络调用,那么就会导致 G 停滞。这时候 M(系统线程)就会被会重新放内核队列中,等待新的一轮唤醒。🎜🎜🎜🎜GM 模型的缺点🎜🎜🎜🎜这么表面的看起来,GM 模型似乎牢不可破,毫无缺陷。但为什么要改呢?🎜🎜在 2012 年时 Dmitry Vyukov 发表了文章《Scalable Go Scheduler Design Doc》,目前也依然是各大研究 Go 调度器文章的主要对象,其在文章内讲述了整体的原因和考虑,下述内容将引用该文章。🎜

当前(代指 Go1.0 的 GM 模型)的 Goroutine 调度器限制了用 Go 编写的并发程序的可扩展性,尤其是高吞吐量服务器和并行计算程序。

实现有如下的问题:

  • 存在单一的全局 mutex(Sched.Lock)和集中状态管理:
    • mutex 需要保护所有与 goroutine 相关的操作(创建、完成、重排等),导致锁竞争严重。
  • Goroutine 传递的问题:
    • goroutine(G)交接(G.nextg):工作者线程(M's)之间会经常交接可运行的 goroutine。
    • 上述可能会导致延迟增加和额外的开销。每个 M 必须能够执行任何可运行的 G,特别是刚刚创建 G 的 M。
  • 每个 M 都需要做内存缓存(M.mcache):
    • 会导致资源消耗过大(每个 mcache 可以吸纳到 2M 的内存缓存和其他缓存),数据局部性差。
  • 频繁的线程阻塞/解阻塞:
    • 在存在 syscalls 的情况下,线程经常被阻塞和解阻塞。这增加了很多额外的性能开销。

GMP 模型

为了解决 GM 模型的以上诸多问题,在 Go1.1 时,Dmitry Vyukov 在 GM 模型的基础上,新增了一个 P(Processor)组件。并且实现了 Work Stealing 算法来解决一些新产生的问题。

再见 Go 面试官:GMP 模型,为什么要有 P?

GMP 模型,在上一篇文章《Go 群友提问:Goroutine 数量控制在多少合适,会影响 GC 和调度?》中已经讲解过了。

觉得不错的小伙伴可以关注一下,这里就不再复述了。

带来什么改变

加了 P 之后会带来什么改变呢?我们再更显式的讲一下。

  • 每个 P 有自己的本地队列,大幅度的减轻了对全局队列的直接依赖,所带来的效果就是锁竞争的减少。而 GM 模型的性能开销大头就是锁竞争。

  • 每个 P 相对的平衡上,在 GMP 模型中也实现了 Work Stealing 算法,如果 P 的本地队列为空,则会从全局队列或其他 P 的本地队列中窃取可运行的 G 来运行,减少空转,提高了资源利用率。

为什么要有 P

这时候就有小伙伴会疑惑了,如果是想实现本地队列、Work Stealing 算法,那为什么不直接在 M 上加呢,M 也照样可以实现类似的功能

为什么又再加多一个 P 组件?

结合 M(系统线程) 的定位来看,若这么做,有以下问题。

  • 一般来讲,M 的数量都会多于 P。像在 Go 中,M 的数量最大限制是 10000,P 的默认数量的 CPU 核数。另外由于 M 的属性,也就是如果存在系统阻塞调用,阻塞了 M,又不够用的情况下,M 会不断增加。

  • M 不断增加的话,如果本地队列挂载在 M 上,那就意味着本地队列也会随之增加。这显然是不合理的,因为本地队列的管理会变得复杂,且 Work Stealing 性能会大幅度下降。

  • M 被系统调用阻塞后,我们是期望把他既有未执行的任务分配给其他继续运行的,而不是一阻塞就导致全部停止。

因此使用 M 是不合理的,那么引入新的组件 P,把本地队列关联到 P 上,就能很好的解决这个问题。

总结

今天这篇文章结合了整个 Go 语言调度器的一些历史情况、原因分析以及解决方案说明。

”GMP 模型,为什么要有 P“ 这个问题就像是一道系统设计了解,因为现在很多人为了应对面试,会硬背 GMP 模型,或者是泡面式过了一遍。而理解其中真正背后的原因,才是我们要去学的要去理解。

知其然知其所以然,才可破局。

以上是再见 Go 面试官:GMP 模型,为什么要有 P?的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何利用PHP和GMP进行大整数的RSA加密和解密算法 如何利用PHP和GMP进行大整数的RSA加密和解密算法 Jul 28, 2023 pm 05:25 PM

如何利用PHP和GMP进行大整数的RSA加密和解密算法RSA加密算法是一种非对称加密算法,广泛应用于数据安全领域。它基于两个特别大的素数和一些简单的数学运算,实现了公钥加密和私钥解密的过程。在PHP语言中,可以通过GMP(GNUMultiplePrecision)库来实现大整数的计算,结合RSA算法实现加密和解密功能。本文将介绍如何利用PHP和GMP库来

再见 Go 面试官:GMP 模型,为什么要有 P? 再见 Go 面试官:GMP 模型,为什么要有 P? Aug 08, 2023 pm 04:31 PM

”GMP 模型,为什么要有 P“ 这个问题就像是一道系统设计了解,因为现在很多人为了应对面试,会硬背 GMP 模型,或者是泡面式过了一遍。而理解其中真正背后的原因,才是我们要去学的要去理解。

php gmp 怎么编译安装 php gmp 怎么编译安装 Nov 08, 2022 am 09:35 AM

php gmp编译安装的方法:1、通过“bzip2 -d gcc-4.1.0.tar.bz2”解压php包;2、执行“tar -xvf gcc-4.1.0.tar”或“tar -xvf *.tar”命令;3、通过“make install”安装gmp即可。

如何使用PHP和GMP实现大数的快速乘法运算 如何使用PHP和GMP实现大数的快速乘法运算 Jul 31, 2023 pm 01:31 PM

如何使用PHP和GMP实现大数的快速乘法运算导言:在计算机科学中,整数运算是非常基础且常用的操作之一。然而,当涉及到大整数时,传统的运算方法会变得低效。本文将介绍如何使用PHP中的GMP(GNUMultiplePrecision)库来实现大数的快速乘法运算,并提供相应的代码示例。GMP库简介GMP库是一个高精度计算库,它提供了大整数的加减乘除、幂运算等功

如何使用PHP和GMP实现RSA加密和解密算法 如何使用PHP和GMP实现RSA加密和解密算法 Jul 28, 2023 pm 11:54 PM

如何使用PHP和GMP实现RSA加密和解密算法RSA加密算法是一种非对称加密算法,广泛应用于信息安全领域。在实际应用中,常常需要使用编程语言来实现RSA加密和解密算法。PHP是一种常用的服务器端脚本语言,而GMP(GNUMultiplePrecision)是一种高精度数学计算库,可以帮助我们进行RSA算法中需要的大数运算。本文将介绍如何使用PHP和GMP

如何使用PHP和GMP生成大质数 如何使用PHP和GMP生成大质数 Aug 01, 2023 pm 01:37 PM

如何使用PHP和GMP生成大质数引言:在密码学和安全领域中,随机生成大质数是非常重要的。PHP的GMP(GNUMultiplePrecision)扩展提供了高精度计算功能,我们可以利用它来生成需要的大质数。本文将介绍如何使用PHP和GMP生成大质数,并提供相应的代码示例。步骤一:安装GMP扩展首先,我们需要确保服务器上已安装并启用GMP扩展。可以通过以下

从头到尾:如何使用php扩展GMP进行大数运算 从头到尾:如何使用php扩展GMP进行大数运算 Aug 02, 2023 am 11:33 AM

从头到尾:如何使用PHP扩展GMP进行大数运算随着互联网的发展,大数据处理成为了我们日常开发中不可或缺的一部分。在很多场景下,我们需要对大于PHP的整数范围(-2^31-1到2^31-1)的数进行运算。在这种情况下,PHP的GMP扩展就可以派上用场了。GMP(GNUMultiplePrecisionArithmeticLibrary)是一个用

PHP和GMP教程:如何计算大数的最小公倍数 PHP和GMP教程:如何计算大数的最小公倍数 Jul 28, 2023 pm 11:51 PM

PHP和GMP教程:如何计算大数的最小公倍数导言:在计算机中,常常需要处理大数运算的问题。然而,由于计算机的存储限制,传统的整数类型无法处理超过一定范围的数字。为了解决这个问题,我们可以使用PHP的GMP(GNUMultiplePrecision)库来进行大数运算。本文将介绍如何使用PHP和GMP库来计算任意两个大数的最小公倍数。什么是最小公倍数?最小公

See all articles