写点什么

Go 语言并发编程的核心 —— GMP 调度模型

作者:Jack
  • 2023-04-17
    广东
  • 本文字数:1304 字

    阅读完需:约 4 分钟

Go语言并发编程的核心 —— GMP调度模型

在 Go 语言中,GMP 调度模型是实现并发的重要手段之一。GMP 调度模型的核心思想是将 M(Machine)、G(Goroutine)和 P(Processor)三个概念分离开来,通过调度器来协调它们之间的关系,从而实现高效的并发。

M(Machine)

M 代表着操作系统中的线程,它是 Go 语言中的执行单位。在程序启动时,Go 语言会创建一定数量的 M,每个 M 都会绑定一个 P。M 的数量默认是 CPU 核心数,但是可以通过 GOMAXPROCS 环境变量来设置。

G(Goroutine)

Goroutine 是 Go 语言中的轻量级线程,它可以与 M 一起调度执行。在程序中,我们可以通过关键字 go 来启动一个 Goroutine,例如:


go func() {    // 处理业务逻辑}()
复制代码


在上面的例子中,我们使用 go 关键字启动了一个 Goroutine,并在其中执行业务逻辑。需要注意的是,Goroutine 是由 Go 语言的运行时(runtime)进行调度的,而不是由操作系统进行调度,因此它具有轻量级、高效等特点。

P(Processor)

Processor 是 Go 语言中的处理器,它负责将 Goroutine 分配给 M 执行。每个 M 都会绑定一个 P,而 P 的数量可以通过 runtime.NumCPU()来获取(不同于 M 的数量)。

调度器

调度器是 GMP 调度模型的核心,它负责将 Goroutine 分配给 M 执行,并在 M 的数量不足时创建新的 M。调度器还可以将 M 从一个 P 转移到另一个 P,以达到负载均衡的目的。


调度器的实现方式比较复杂,但是它的工作原理可以简单概括如下:


  • 当一个 Goroutine 被启动时,它会被放入一个全局的运行队列中(称为全局队列)。

  • 当一个 M 空闲时,它会从全局队列中获取一个 Goroutine,并开始执行它。

  • 当一个 Goroutine 阻塞时,它会被放入一个本地的等待队列中(称为本地队列)。

  • 当一个 M 中的本地队列为空时,它会从全局队列中获取一批 Goroutine,并将它们放入本地队列中。

  • 当一个 P 中的本地队列为空时,它会从其他 P 中的本地队列中获取一批 Goroutine,并将它们放入本地队列中。

  • 当一个 M 执行时间过长时,调度器会中断它的执行,并将它的状态保存到一个全局的挂起队列中。下次该 M 被分配到执行时,它会从挂起队列中恢复状态,并继续执行。

  • 当一个 M 执行的 Goroutine 数量达到一定阈值时,调度器会将它的状态保存到一个全局的休眠队列中。下次该 M 被分配到执行时,它会从休眠队列中恢复状态,并继续执行。


下面我们来看一个简单的示例,它通过启动多个 Goroutine 来计算斐波那契数列的值:


package main
import "fmt"
func main() { for i := 0; i < 10; i++ { go func() { fmt.Println(fib(40)) }() }}
func fib(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2)}
复制代码


在上面的例子中,我们启动了 10 个 Goroutine,并在其中计算斐波那契数列的值。由于斐波那契数列的计算是 CPU 密集型的,因此这个程序会利用 GMP 调度模型来实现高效的并发。

注意事项

在使用 GMP 调度模型时,需要注意以下几点:


  • 不要在 Goroutine 中阻塞或者进行长时间的计算,这会导致 M 被挂起或者休眠,从而影响程序的性能。

  • 不要在 Goroutine 中访问共享资源时不加锁,这会导致数据竞争,从而引发难以排查的 bug。

  • 不要将过多的 Goroutine 放入全局队列中,这会导致调度器的性能下降,从而影响程序的性能。

  • 不要将过多的 M 创建出来,这会导致系统资源的浪费,从而影响程序的性能。

发布于: 刚刚阅读数: 6
用户头像

Jack

关注

还未添加个人签名 2019-05-12 加入

作为一名技术追求者,我对科技、编程和创新充满热情。我始终关注最新的商业趋势和技术发展,努力将其应用于实践中,从而推动技术创新和改进。我善于思考和分析,具备较强的解决问题的能力和团队合作精神。

评论

发布
暂无评论
Go语言并发编程的核心 —— GMP调度模型_Jack_InfoQ写作社区