关于golang:GOGMP模型

8次阅读

共计 836 个字符,预计需要花费 3 分钟才能阅读完成。

在 Go 中,线程是运行 goroutine 的实体,调度器的性能是把可运行的 goroutine 调配到工作线程上。

  • 全局队列(Global Queue):寄存期待运行的 G。
  • P 的本地队列:同全局队列相似,寄存的也是期待运行的 G,存的数量无限,不超过 256 个。新建 G ’ 时,G’ 优先退出到 P 的本地队列,如果队列满了,则会把本地队列中一半的 G 挪动到全局队列。
  • P 列表:所有的 P 都在程序启动时创立,并保留在数组中,最多有 GOMAXPROCS(可配置) 个。
  • M:线程想运行工作就得获取 P,从 P 的本地队列获取 G,P 队列为空时,M 也会尝试从全局队列拿一批 G 放到 P 的本地队列,或从其余 P 的本地队列偷一半放到本人 P 的本地队列。M运行 G,G 执行之后,M 会从 P 获取下一个 G,一直反复上来。
    Goroutine 调度器和 OS 调度器是通过 M 联合起来的,每个 M 都代表了 1 个内核线程,OS 调度器负责把内核线程调配到 CPU 的核上执行。

无关 P 和 M 的个数问题

1、P 的数量
由启动时环境变量 $GOMAXPROCS 或者是由 runtime 的办法 GOMAXPROCS() 决定。这意味着在程序执行的任意时刻都只有 $GOMAXPROCSgoroutine在同时运行。

2、M 的数量
go 语言自身的限度:go 程序启动时,会设置M 的最大数量,默认 10000. 然而内核很难反对这么多的线程数,所以这个限度能够疏忽。
runtime/debug 中的 SetMaxThreads 函数,设置 M 的最大数量
一个 M 阻塞了,会创立新的 M。
M 与 P 的数量没有相对关系,一个 M 阻塞,P就会去创立或者切换另一个 M,所以,即便 P 的默认数量是1,也有可能会创立很多个M 进去。

3、P 和 M 何时会被创立

  • P何时创立:在确定了 P 的最大数量 n 后,运行时零碎会依据这个数量创立 nP
  • M何时创立:没有足够的 M 来关联 P 并运行其中的可运行的G。比方所有的 M 此时都阻塞住了,而 P 中还有很多就绪工作,就会去寻找闲暇的 M,而没有闲暇的,就会去创立新的 M。

参考资料
Golang 的协程调度器原理及 GMP 设计思维

正文完
 0