【Go】面试必会!两张图讲清Go语言并发调度策略

本文深入探讨Go语言的GMP模型,解析Goroutine的调度策略,包括何时触发调度、如何选择执行的Goroutine,以及调度的具体算法。通过图文并茂的方式,帮助读者理解Go运行时的并发管理机制。
摘要由CSDN通过智能技术生成

这位 Gopher 你好呀!如果觉得我的文章还不错,欢迎一键三连支持一下!文章会定期更新,同时可以微信搜索【凑个整数1024】第一时间收到文章更新提醒⏰

背过面试“八股文”的 Gopher 们肯定了解 Go 语言运行时(Go runtime)的 GMP 模型。Go runtime 时通过 GMP 模型可以完成对 goroutine 的创建、调度、销毁等声明周期的管理,实现 Go 语言优秀的高并发性能。本文将重点关注 GMP 模型的的调度策略,聚焦 Go runtime 的两个问题:

  1. Go runtime 什么时候会触发调度?有哪几种情况?
  2. Go runtime 调度 goroutine 的算法是什么?

GMP 模型

进入正篇内容前先对前置知识——GMP 模型进行一个大致回顾。由于 GMP 模型本身并不是本文重点,这里只进行简单的概念梳理。

G

G 是 goroutine 的抽象,在文中大部分时候 goroutine 就是 G,在 Go 源码中是 g 类型。G 有自己的运行栈、状态、通用寄存器值、要执行任务函数的地址等,G 需要与 P 进行绑定才可以执行。

M

M 是对操作系统线程的抽象,是拿着 G 所提供的执行上下文,真正去执行的类型,在 Go 源码中是 m 类型。M 同样需要与 P 绑定,由 P 来作为代理去执行 G,因此 M 不需要与 G 进行强绑定,无需保存 G 状态信息,这样 G 也可以实现跨 M 执行。

值得注意的是,每个 M 会保存一个特殊 G 的指针,这个 G 就是 g0:它不用于执行用户函数代码,只用于执行调度策略,是本文内容中的一个重要角色。

P

P 可以理解为线程本地的调度器,或处理器资源池,在 Go 源码中是 p 类型。P 是 GMP 模型的中枢,对 M 与 G 进行动态有机结合。P 中管理着若干 goroutine 调度相关的资源与上下文,如线程本地 G 队列、本地内存池(mcache)、对象缓存等。

对于 G 而言,P 就可以看作是处理器,只有被 P 调度,G 才能够被执行;对于 M 而言,P 就是其执行 G 的代理,无需 M 自己去关心繁杂调度细节(找到可执行 G、内存资源分配等)。

调度策略

Goroutine 的调度无非关注的就是两点:什么时候需要调度,以及如何找到下一个需要执行的 goroutine,这也正好分别对应了文章开头的两个问题。

稍微往底层看下,调度就是一个普通的 G 由于一定的原因需要与当前 M 解绑,而 M 又需要有下一个可以执行的 G。实现这样的调度,就需要用户 G 与 g0 之间进行“反复横跳”。这里我们给出一张宏观的调度图:

goroutine 调度宏观图

执行用户代码的普通 G 调用 mcall() 切换到 g0,g0 通过 schedule() 调度的核心方法,找到下一个可执行的 G,更新新旧 G 的状态,将新 G 与 M 进行绑定,最终调用 gogo() 方法从 g0 切换到新的 G 去执行。

函数mcall()gogo() 就是实现用户 G 与 g0 之间“反复横跳”的关键,是对偶的存在关系。

调度时机与类型

本小节我们来回答第一个问题:什么时候会触发调度?有哪几种情况?

Goroutine 触发调度的情况可以分为以下几种类型:

  1. G 正常结束:这种是最简单的情况,G 在一次调度中就完成了执行任务(也有可能手动执行了 runtime.GoExit()),切换到 g0 去执行 goexit0_m() 函数将当前 G 置为死亡(_Gdead)状态,发起新一轮调度;

  2. 主动调度:一种用户 G 主动让渡的方式,当前 G 主动让出 M,这是 goroutine “协程” 概念的体现(严格来说 Goroutine 不是协程,而是绿色线程,协程主打协作,只有主动让渡,而 Goroutine 会进行)。其主要方式是,用户在执行代码中调用了 runtime.Gosched 方法,此时当前 G 会当让出执行权,主动进行队列等待下次被调度执行。具体代码可以参考 runtime/proc.go:GoSched(),在这个函数中会切换到 g0 去执行 gosched_m() 函数;

func Gosched() {
   
    checkTimeouts()
    mcall(gosched_m)
}
  1. 被动调度:当 G 因为不满足某种执行条件,G 会陷入阻塞状态(准确说是 _Gwaiting),常见的如等待获取互斥锁 sync.Mutex</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值