MPG

非常强大的管理goroutine和系统内核线程的调度器
M(achine):操作系统的主线程(物理线程) P(processor):协程执行需要的上下文(中介) G(oroutine): 协程
    
在宏观上说,Goroutine与Machine因为Processor的存在,形成了多对多的(M:N)关系,M个用户线程对应N个系统线程,缺点是增加了调度器的实现难度

Goroutine是Go语言中并发的执行单位.底层使用协程实现。
Go在语言层面实现了调度器,同时对网络,IO库进行了封装处理,屏蔽了操作系统层面的复杂的细节,在语言层面提供统一的关键字支持。

通过
runtime.GOMAXPROCS()设置同时操作的操作系统线程,默认CPU可用核心数。

其中goroutine包含正在运行的,和阻塞的

 

 

1、当一个Goroutine被创建时,Goroutine对象被压入Processor的本地队列或者Go运行时的全局Goroutine队列
2、Processor唤醒一个Machine,如果Machine的waiting队列没有等待被唤醒的Machine,则创建一个(最大值10000),Processor获取到Machine后,与Machine绑定,并执行此Goroutine
runtime/runtime2.go
runtime/proc.go
func schedinit(){
// 设置对打的M数量 sched.maxcount = 10000 } 3、Machine执行过程中,随时会发生上下文切换,当发生上下文切换时,需要对执行现场惊醒保护,以便下次被调度执行时进行现场恢复。
    Go调度器中Machine的栈保存在Goroutine对象上,只需要将Machine所需要的寄存器保存到Goroutine对象上
4、如果此时Goroutine任务还没有执行完,Machine可以将Goroutine重新压入Processor的队列,等待下一次被调度执行 5、如果执行过程遇到阻塞并阻塞超时,Machine会与Process分离,并等待阻塞结束。此时Processor可以继续唤醒Machine执行其它的Goroutine,
  当阻塞结束时,Machine会尝试偷取一个Processor,如果失败,这个Goroutine会被加入到全局队列中,然后Machine将自己转入waiting队列,等待被再次唤醒

 

当一个正在与某个 M 对接并运行着的 G,需要因某个事件(比如等待 I/O 或锁的解除)而暂停运行的时候,
调度器总会及时地发现,并把这个 G 与那个 M 分离开,以释放计算资源,供那些等待运行的 G 使用。
而当一个 G 需要恢复运行的时候,调度器又会尽快地为它寻找空闲的计算资源(包括 M)并安排运行。
另外,
当 M 不够用时,调度器会帮我们向操作系统申请新的系统级线程,
而当某个 M 已无用时,调度器又会负责把它及时地销毁掉。

正因为调度器帮助我们做了很多事,所以我们的 Go 程序才总是能高效地利用操作系统和计算机资源。
程序中的所有 goroutine 也都会被充分地调度,其中的代码也都会被并发地运行。

 

posted @ 2020-01-12 14:12  慕沁  阅读(574)  评论(0)    收藏  举报