Golang 天生支持并发,Goroutine是Go 最吸引人的地方,采用的是CSP并发通信模型。到底Go是怎么支持高并发的呢?这里就需要说一说Golang 的MPG模型。

  1. M 代表着一个内核线程 ,一个M就是一个内核线程,goroutine就是跑在M之上的

  2. P 代表着(Processor)处理器, 它的主要用途就是用来执行goroutine的,所以它也维护了一个可运行的goroutine队列,和自由的goroutine队列,里面存储了所有需要它来执行的goroutine。

  3. G 代表着goroutine 实际的数据结构,并维护者goroutine 需要的栈、程序计数器以及它所在的M等信息。

  4. Sched 代表着一个调度器 它维护有存储空闲的M队列和空闲的P队列,可运行的G队列,自由的G队列以及调度器的一些状态信息等。

一张图就可以说明MPG模型:

图中的“土拨鼠”代表的就是M,“推车”代表的是P,“木块”代表的就是G。在这张图外还存在一个特殊的”土拨鼠“这个”土拨鼠“就是”包工头“Sched

从图中我们可以看到“土拨鼠“不停地将“木块“搬运到“推车“上,然后推去烧。在这个过程中可能出现“土拨鼠“因为累坏了,而处理的速度变慢的情况,这个时候“包工头“就出现了,“包工头“非常体贴的将这个“土拨鼠“的“推车“交给其他“土拨鼠“去处理。如果一个“土拨鼠“的“推车“里面的“木块“装的太多,“包工头“也会让其它的“土拨鼠“去帮忙拿出一些来。当“包工头“发现现有的“土拨鼠“已经忙不过来的时候,就回去找一些新的“土拨鼠“过来,并给他们配发“推车“。直到所有的“木块“都烧完为止。

上面说到的几种情况:

  1. “土拨鼠”累坏了,形容的是IO等耗时的操作。

  2. 其他“土拨鼠”帮忙,形容的是工作窃取算法(work stealing),这个算法在很多语言中都有应用,例如Java中的Fork/Foin。

在Golang中土拨鼠默认的数量是CPU的核数,土拨鼠通过CSP模型沟通。

参考资料: