浅析Go中的MPG模式(一)

Goroutine(协程)
首先了解一下协程(goroutine)这个东西
一、Go线程(主线程,通常称为线程,有的大佬们也直接叫进程),也可理解为进程。是一个物理级线程,重量级的,很是耗费CPU资源网络


二、一个线程上能够有多个协程(goroutine),协程是轻量级的线程(go对于线程进行的特殊处理)。逻辑态,消耗资源相对少。按照消耗资源能够这样排序:进程 >= 主线程 > 子线程 >= 协程并发


三、Go协程特色
(1)有独立的栈空间
(2)共享程序堆空间
(3)调度由用户(程序)控制
(4)协程是轻量级的线程ide


四、主线程退出了,协程即便未执行完毕也会中止,退出程序。操作系统


MPG模式:

一、解释一下MPG含义:
M(Machine):操做系统的主线程
P(Processor):协程执行须要的资源(上下文context),能够看做一个局部的调度器,使go代码在一个线程上跑,他是实现从N:1到N:M映射的关键
G(Gorountine):协程,有本身的栈。包含指令指针(instruction pointer)和其它信息(正在等待的channel等等),用于调度。一个P下面能够有多个G线程


二、**P的数量能够经过GOMAXPROCS()来设置,**他其实表明了真正的并发度,即有多少个goroutine能够同时运行。P同时也维护着G(协程)的队列(称之为runqueue进程队列)。Go代码中的M每有一个语句被执行,P就在末尾加入一个G(从runqueue队列中取出来的),在下一个调度点(P),就从runqueue队列中取出G。(图片来源于网络,太多相似的忘了在哪截的)
在这里插入图片描述指针


三、P能够在OS线程(主线程,或者是M)被阻塞时,转到另外一个OS线程(M)!Go中的调度器保证有足够的线程来运行全部的P。当启用一个M0中的G0被sysCall(系统调用)的时候,M0下面的P转给另外一个线程M1(能够是建立的,也能够是本来就存在的)。M1接受了P(包括P所带的runqueue的队列里面全部状态的G,但不包括已经被syscall的G0),继续运行。而M0会等待执行syscall的G0的返回值。当G0的syscall结束后,他的主线程M0会尝试取得一个P来运行G0,通常状况下,他会从其余的M里面偷一个P过来,若是没有偷到的话就会把G0放到一个Global runqueue(全局进程队列)中,而后把本身(M0)放进线程池或者转为休眠状态。协程


四、Global runqueue是各个P在运行完本身的本地的goroutine runqueue后用来拉取新goroutine的地方。P也会周期性的检查这个Global runqueue上的goroutine,不然全局runqueue上的goroutine可能得不到执行而饿死。。。
九、当P中的runqueue队列里面的G所有执行完毕以后,他会偷取未执行完的P中的G(偷取一半)!blog