Golang 的三个核心调度模块:G、M 和 P

当涉及 Golang 的 g、m 和 p 时,我们要理解的是 Go 语言运行时(runtime)的内部机制,以及它们之间是如何协作以支持高效的并发和并行的。

  1. G(Goroutine):Goroutine 是轻量级的执行单位,它类似于线程,但比线程更轻量级、更易于创建和管理。每个 Goroutine 都会绑定到一个 P(Processor)上,P 会负责调度 Goroutine 的执行。Goroutine 之间的切换是由 Go 运行时调度器负责的,而不需要开发者手动干预。
  2. M(Machine):M 是执行 Goroutine 的执行上下文,也可以看作是一个执行线程。Go 运行时会创建多个 M,每个 M 都会关联一个内核线程。M 的数量是动态变化的,它们会根据需要进行创建和销毁。M 负责执行 Goroutine,并在需要时进行上下文切换。
  3. P(Processor):P 是调度上下文,它的主要作用是从全局 Goroutine 队列中获取 Goroutine 并分派给 M 进行执行。P 维护了一组 Goroutine,并在 M 上调度这些 Goroutine 的执行。一个 M 上可以关联一个或多个 P,但一个 P 只会关联一个 M。

这三者之间的协作如下:

  1. 当一个 Goroutine 准备好运行时,它会被放入全局 Goroutine 队列中,等待被分配到一个 P 上执行。
  2. 空闲的 M 会从全局 Goroutine 队列中获取一个 Goroutine,并开始执行它。M 会执行 Goroutine 中的函数,直到遇到阻塞操作或 Goroutine 自愿让出 CPU。
  3. P 会管理一组 Goroutine,并为 M 分派 Goroutine。P 会周期性地检查每个关联的 M 的运行状态,以确保它们不会长时间阻塞。
  4. 如果一个 M 长时间阻塞(例如,因为系统调用),P 可以将与该 M 关联的 Goroutine 分派给其他 M 执行,以充分利用 CPU。
  5. 当 Goroutine 执行完成或自愿让出 CPU 时,M 会从 P 获取下一个要执行的 Goroutine。

协作过程如下:

  1. G 的状态从 Gidle(空闲)变为 Grunnable(可运行),表示它已经准备好执行。
  2. P 的调度器会周期性地检查是否有可运行的 Goroutine。如果有,它会将一个 Goroutine 分配给一个空闲的 M。
  3. M 从 P 获取 Goroutine,并开始执行它。当 Goroutine 遇到阻塞操作或自愿让出 CPU 时,M 会重新归还 Goroutine 并继续从 P 获取新的 Goroutine。
  4. 当 M 长时间阻塞(如系统调用)时,P 可以将关联的 Goroutine 分派给其他 M。
  5. G 的状态可能变为 Gwaiting(等待),表示它在等待某个条件满足。一旦条件满足,G 可以重新变为 Grunnable

通过这种方式,Goroutine 在 M 和 P 的协作下实现了高效的并发和并行执行。Goroutine 的创建和销毁成本很低,而 M 的创建和销毁会根据系统负载动态调整,使得 Golang 能够在多核处理器上充分利用硬件并行性。值得注意的是,Goroutine 的调度是由运行时自动处理的,开发者无需手动控制。这种机制使得 Golang 能够高效地支持大规模并发编程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值