初探 Go 语言并发 M-P-G 模型

kenticny

Go 语言自从诞生以来就自带“高并发”的buff,而并发编程也是当今开发环境的一个大方向了。目前的各大语言基本上也都提供了原生多线程的并发编程模式。但是 Go 语言的并发模型和 C++,Java 的并发模型是有区别的。

传统的并发模型是将线程直接与操作系统内核线程进行一对一的绑定,线程调度完全交由操作系统去完成。目前的很多语言都是采用的这种模型,比如 C++,Java 等语言,这种模型由于将线程的管理及调度都交由操作系统完成,所以实现起来简单;也正是因为这个原因,会导致线程之间的上下文切换频繁,产生性能问题。

而 Go 语言是通过 Goroutine 来实现并发操作的,与线程不同的是,Goroutine 的调度并不是完全有操作系统来进行的。而且 Goroutine 要比线程更加轻量级,所有很多地方将 Goroutine 称为“协程”,但是 Goroutine 和传统意义上的协程并不完全等同。传统的协程是由编程语言或者第三方库直接在进程中实现调度,并不通过系统内核调度。而 Goroutine 则是属于一种介于传统多线程模型和协程模型之间的混合类型,其中既包括了语言自身实现的调度,也通过某种方式关联到系统线程,这种模型就是 M-P-G 模型。

首先介绍下这三个对象分别是什么:

  • M: 即 Machine,和操作系统线程进行绑定,由操作系统进行调度。是真正执行 Goroutine 的资源。

  • P: 即 Processor,和 M 为一对一关系,提供了执行的上下文环境。包含 G(Goroutine) 队列。

  • G: 即 Goroutine,为 Go 语言中独立的执行单元。需要加入到 P 的任务队列才可能被执行。

那么这三者之间是怎样完成调度的呢?

Go Schedule

  1. 在 Go 语言中可以通过 go 关键字来创建 Goroutine。Goroutine 被创建以后会加入到一个 P 的任务队列中,然后和 P 绑定的 M 则会从 P 的任务队列中取出 G 来执行。

  2. 在 P 的任务队列被全部执行完之后,会从全局 Global 的任务队列中取出 G 来执行。

  3. 如果全局任务队列为空,则会随机挑选另一个 P,将其任务队列中一半的任务移动到自己的任务队列。

以上就是 Go 语言调度 M-P-G 模式的概念和调度过程,当然其中还有很多细节没有提到,比如在调度过程中发生阻塞后要怎样处理,因为这些情况还包含更复杂的逻辑,所以之后如果有机会单独写博客介绍。

  • 本文标题:初探 Go 语言并发 M-P-G 模型
  • 本文作者:kenticny
  • 创建时间:2015-04-16 23:32:18
  • 本文链接:https://luyun.io/2015/04/16/golang-concurrent-m-p-g-model/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论
此页目录
初探 Go 语言并发 M-P-G 模型