golang调度器原理与GMP模型设计思想

⼀、Golang“调度器”由来

协程(co-routine), 引发的问题?(M:线程 N:协程)

N:1  1.⽆法利⽤多个CPU  2.出现阻塞的瓶颈

1:1   1.跟多线程/多进程模型⽆异  2.切换协程成本代价昂贵

M:N  1.能够利⽤多核 2.过于依赖协程调度器的优化和算 法

go-routine的优化?

内存占⽤ ⼏KB ⼤量开辟

灵活调度 切换成本低

早期的Go的调度器 基本的全局Go队列和⽐较传统的 轮询利⽤多个thread去调度

弊端

1. 创建、销毁、调度G都需要每个M获取锁,这就形成了激烈的锁竞争。

2. M转移G会造成延迟和额外的系统负载。

3. 系统调⽤(CPU在M之间的切换)导致频繁的线程阻塞和取消阻塞操作增加了系统开销。

⼆、Goroutine调度器的GMP模型的设计思想

 GMP模型简介:

G:goroutine 协程

M:thread 内核线程

P:processor 处理器

全局队列 存放等待运⾏的G

P的本地队列:  1存放等待运⾏的G 2数量限制 不超过256G 3 优先将新创建的G放在P的本地队 列中,如果满了会放在全局队列 中

P列表: 1程序启动时创建 2最多有GOMAXPROCS个(可配置)

M列表: 当前操作系统分配到当前Go程序的内核线程数

P的数量: 1.环境变量$GOMAXPROCS  2.在程序中通过runtime.GOMAXPROCS() 来设置

M的数量问题: 1.Go语⾔本身 是限定M的最⼤量是10000(忽略) 2.runtime/debug包中的SetMaxThreads函数来设置 3.有⼀个M阻塞,会创建⼀个新的M 4.如果有M空闲,那么就会回收或者睡眠

调度器的设计策略

1.复⽤线程 避免频繁的创建、销毁线程,⽽是对线程的复⽤。

(1)work stealing机制 当本线程⽆可运⾏的G时,尝试 从其他线程绑定的P偷取G,⽽不 是销毁线程。

(2)hand off机制 当本线程因为G进⾏系统调⽤阻 塞时,线程释放绑定的P,把P转 移给其他空闲的线程执⾏。

2.利⽤并⾏ GOMAXPROCS设置P的数量,最多有GOMAXPROCS个线程分布在多个CPU上同时运⾏。

3.抢占 在coroutine中要等待⼀个协程主动让出CPU才执⾏下⼀个协程,在Go 中,⼀个goroutine最多占⽤CPU 10ms,防⽌其他goroutine被饿死

4.全局G队列 当M执⾏work stealing从其他P偷不到G时,它可以从全局G队列获取G。

 三.“go func()” 经历了什么过程

1、我们通过 go func()来创建⼀个goroutine;

2、有两个存储G的队列,⼀个是局部调度器P的本地队列、⼀个是全局G队列。新创建的G会先 保存在P的本地队列中,如果P的本地队列已经满了就会保存在全局的队列中;

3、G只能运⾏在M中,⼀个M必须持有⼀个P,M与P是1:1的关系。M会从P的本地队列弹出⼀个可执 ⾏状态的G来执⾏,如果P的本地队列为空,就会想其他的MP组合偷取⼀个可执⾏的G来执⾏;

4、⼀个M调度G执⾏的过程是⼀个循环机制;

5、当M执⾏某⼀个G时候如果发⽣了syscall或则其余阻塞操作,M会阻塞,如果当前有⼀些G在执⾏, runtime会把这个线程M从P中摘除(detach),然后再创建⼀个新的操作系统的线程(如果有空闲的线程可 ⽤就复⽤空闲线程)来服务于这个P;

6、当M系统调⽤结束时候,这个G会尝试获取⼀个空闲的P执⾏,并放⼊到这个P的本地队列。如果获取不 到P,那么这个线程M变成休眠状态, 加⼊到空闲线程中,然后这个G会被放⼊全局队列中。

四.调度器的⽣命周期

M0 M0是启动程序后的编号为0的主线程,这个M对应的实例会在全局变量runtime.m0中,不需要在heap 上分配,M0负责执⾏初始化操作和启动第⼀个G, 在之后M0就和其他的M⼀样了。

G0 G0是每次启动⼀个M都会第⼀个创建的gourtine,G0仅⽤于负责调度的G,G0不指向任何可执⾏的函数, 每个M都会有⼀个⾃⼰的G0。在调度或系统调⽤时会使⽤G0的栈空间, 全局变量的G0是M0的G0。

五.可视化的GMP编程

创建trace⽂件 f, err := os.Create("trace.out")

启动trace trace.Start(f)

停⽌trace trace.Stop()

go build 并且运⾏之后,会得到⼀个trace.out⽂件

go tool trace trace.out

通过http://127.0.0.1:33479进⾏访问

通过Debug trace查看GMP信息 

原文地址:https://www.cnblogs.com/peteremperor/p/13651940.html