Go的CSP并发模型实现M, P, G简介

GMP概念简介

G: goroutine(协程,也叫用户态线程)

M: 工作线程(内核态线程)

P: 上下文(也可以认为是cpu,逻辑cpu数量,可以在程序启动的时候设置这个数量,gomaxprocs函数设置)

GMP 模型

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

  1. 全局队列(Global Queue):存放等待运行的 G。
  2. P 的本地队列:同全局队列类似,存放的也是等待运行的 G,存的数量有限,不超过 256 个。新建 G'时,G'优先加入到 P 的本地队列,如果队列满了,则会把本地队列中一半的 G 移动到全局队列。
  3. P 列表:所有的 P 都在程序启动时创建,并保存在数组中,最多有 GOMAXPROCS(可配置) 个。
  4. M:线程想运行任务就得获取 P,从 P 的本地队列获取 G,P 队列为空时,M 也会尝试从全局队列拿一批 G 放到 P 的本地队列,或从其他 P 的本地队列偷一半放到自己 P 的本地队列。M 运行 G,G 执行之后,M 会从 P 获取下一个 G,不断重复下去。

有关 P 和 M 的个数问题

1.P 的数量:

由启动时环境变量 GOMAXPROCS 或者是由 runtime 的方法 GOMAXPROCS() 决定。这意味着在程序执行的任意时刻都只有 GOMAXPROCS 个 goroutine 在同时运行。
2. M 的数量:

(1) go 语言本身的限制:go 程序启动时,会设置 M 的最大数量,默认 10000. 但是内核很难支持这么多的线程数,所以这个限制可以忽略。

(2) runtime/debug 中的 SetMaxThreads 函数,设置 M 的最大数量

(3) 一个 M 阻塞了,会创建新的 M。

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 会被放入全局队列中。

相关推荐
deepin_sir37 分钟前
10 - 函数
开发语言·python
z落落1 小时前
C#String字符串
开发语言·c#·php
猫头虎-前端技术1 小时前
JS 作用域与闭包:从变量提升到闭包陷阱的超详细解析
开发语言·javascript·云计算·bootstrap·ecmascript·openstack·perl
枫叶林FYL1 小时前
项目十:事件溯源仓储管理系统(WMS)仿真实现
开发语言·python
繁华落尽,倾城殇?2 小时前
[C++11] : atomic,nullptr,default/delete,enum class
开发语言·c++·c++11·nullptr·atomic·enum class·default/delete
01_ice2 小时前
C语言数据在内存中的存储
c语言·开发语言
代码村新手2 小时前
C++-二叉搜索树
开发语言·c++
吃好睡好便好4 小时前
创建魔方矩阵和单位矩阵
开发语言·人工智能·学习·线性代数·matlab·矩阵
影寂ldy4 小时前
C#数组的属性和方法(Clear / Copy / IndexOf )
开发语言·javascript·c#
i7i8i9com4 小时前
Hermes Agent 安装记录
开发语言·bash·hermes