MPG 模式的介绍 | 学习笔记

简介: 快速学习 MPG 模式的介绍

开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程MPG 模式的介绍】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/626/detail/9749


MPG 模式的介绍

 

内容介绍

一,MGP 模式基本介绍

二,MPG 模式运行的状态1

三,MPG 模式运行的状态2

 

一,MGP 模式基本介绍

Go 的调度器内部有三个重要的结构: M,P,S
M:代表真正的内核 0S 线程,和 POSIX 里的 thread 类似,真正起作用的
G:代表一个 goroutine,有自己的栈,instruction pointer 和其他信息(正在等待的 channel 等等),用于调度。
P:代表调度的上下文,可以把它看做一个局部的调度器,使 go 代码在一一个线程上跑,是实现从 N:1到 N:M 映射的关键。

image.png


第一个结论,看一下主线程,它是一个物理线程,主线程是直接作用在一个 cpu 上面的是重量级的非常的耗费 cpu 资源组建,一个物理级的操作系统来控制的携程,是从主线程开启的是轻量级的线程是相对来说资源消耗相对较小形成机制重要的一个特点可以轻松的开启三个携程其他编程,语言的并发机制一般是基于线程那开启过的线程资源耗费大。这个快速入门的一个小节先把它反射到里面后接着快速度它关掉。

快速入门重点就是做了三个的缩影。接着,来检验一下 gro ton,的一个调度模型是什么机制。这个 MPG 一般就是面试。第一个代表是操作系统的一个主线测。M 是一种相当于是一个物理极限,所以它比较费资源。P 可以认为是一个在整个执行过程中的一个上下文环境,上下文环境是在很多编程语言里面都会有提到东西,上下文环境,可以简单的说运行的时候需要一些资源或者他的一个当时的操作系统的状态。就好像这儿有一个 M 主线程。在我们运行过程中,比如说在一个位置,需要开启一个携程,那么在携程起来的时候需要有一个商业的环境。就好像一个人一样,这个人是在什么地方生活得有空气,有水。一个一个连起来时候,它要依赖于当前操作系统还有这个内存的分配,以及还有没有可分配,这些都可以成为一个很重要的概念,就是他需要的资源和它运行。

创建这个过程中,比如说在这个专业的运行过程,突然在这个这个地方,需要去开启一个携程,那么这个携程网还可以形成一个规定它可以形成一个对比,比如又需要开发一个中间一个鞋城,这又算是一个节点,或者是图文的一个环境,那么从这又可以继续开启另外的其他的携程,同样也可以形成一个,形成一个对立,形成对立相对简单。

 

二,MPG 模式运行的状态1

image.png

当前程序有三个 M,如果三个 M 都在一一个 cpu 运行, 就是并发,如果在不同的 cpu 运行就是并行。
M1,M2,M3正在执行一个 G, M1的协程队列有三个,M2 的协程队列有3个,M3 协程队列有2个。
从上图可以看到: Go 的协程是轻量级的线程,是逻辑态的,Go 可以容易的起上万个协程。
其它程序 c/java 的多线程, 往往是内核态的,比较重量级,几千个线程可能耗光 cpu。

要理解这个事首先得了解操作系统是怎么运用线程的。一个线程就是一个栈加一堆资源。操作系统一会让 cpu 跑线程 A,一会让 cpu 跑线程 B,靠 A  B 的栈来保存 A  B 的执行状态。每个线程都有自己的栈。
但是线程又贵,所以 go 发明了 goroutine. 大致就是说给每个 goroutine 个分配在 heap 里面的栈来模拟线程栈。比有3个 goroutine, A,B,C, 就在 heap 开发出三个栈。然后 Go 让一个单线程的 scheduler 开始这三个栈。相当于{ A(); B(); C() },连续的,串行的跑。和操作系统不太一样的是,操作系统可以随时随地把线程停掉,切换到另一个线程。这个单线程的 scheduler 那个能力,就是 user space  的一段朴素的代码,他跑 A 的时候控制权是在 A 的代码里面。A 自己不退出也没有其他办法。所以 A 跑一小段后需要主动主动反馈进行休息, 这时候可以看做A返回了。A 返回了 B 就可以跑了,然后 B 小段保存状态,返回,然后 C 再跑。C 跑一段返回。
样跑完 A(); B(); C()}之后, 我们发现,好像他们都只跑了小段。所以外面要包一个循环,大致是:
goroutine_ list = [A, B, Cwhile (goroutine) :for goroutine in goroutine_ list:r = goroutine()if r. finished():goroutine_ list. remove(r)

当前程序有三个 M,三个 M 有三个 em,如果三个都运行在一个 cpu,就称之为并发。

概念第二点 M1M2M3正在执行一个。可以知道 M1现在正在执行一个 G。携程正在实行,同样M来执行一个 G,也在同时执行。

在 P 的地方,它可以开启 G,这种多的情况下,可以进行一个队列,这是它的一个模式。每个携程可以去完成的一个任务。那么其他程序比如说 C,是多线程,线程往往是内核态的比较重量级,几千个线程就可能耗光 cpu,耗费 cpu 这是他的第一种状态

 

三,MPG 模式运行的状态2

分成两个部分来看。
原来的情况是 MO 主线程正在执行 G0 协程,另外有三个协程在队列等待。
如果 G0 协程阻塞,比如读取文件或者数据库等。
这时就会创建 M1主线程(也可能是从已有的线程池中取出 M1),并且将等待的3个协程挂到 M1下开始执行,M0 的主线程 下的 GO 仍然执行文件 io 的读写。
这样的 MPG 调度模式,可以既让 G0 执行,同时也不会让队列的其它协程一直阻塞, 仍然可以并发/并行执行。
等到 G0 不阻塞了,M0 会被放到空闲的主线程继续执行(从已有的线程池中取),同时 G0 又会被唤醒。

image.png

举一个动态的 MPG 运行的一个状态二。

比如现在情况,分成两部分来看是 M0 M0,这就是主线程正在执行,等待如果遇到了一个 go 携程被阻塞什么情况下会堵塞这个一个携程,例如文件或者数据库,因为文件时不知道要花多少时间,操作系统它就是这个携程,底层就会等待一个文件到底要多久不知道,对计算机来说已经很长了,认为在读文章的时候,cpu 有点浪费时间等,所以此时可能会做这样的事情 cpu 他们一个空闲状态就会创建一个叫 M1的,一个主题,也有可能这个事情已经从有了一个现场秩序,只有根据当时的情况,M0再运行或者有可能维护一个线程池。 

例如里面有可能预留一个,或者一可能没有,这个就跟操作系统底层相关联,如果有,就把这个 M 一个拿过来并进行唤醒,让它工作,如果没有,就出现这样的情况,跟操作系统底层有关系,跟上下文环境有关系。M 用就是原来进行等待现在立即就来工作。并且将等待的三个携程挂到 M1下面去执行。其实本质上来说可能就是一个列表,也可能是一个队列的数据结构,完全可以做挂到,可以简单的认为让这个 M1指向。对于一个队列,我们可以把这个地址给他,就相当于挂到上面后就开始执行,那么 F0这个主线程,叫做功能仍然执行这个,他原来的读写,例如 MPG 模式既可以正常的读文件,文件同时也不会让队列中的其他一直堵塞。此时这个东西,就有效的把 cpu 运行起来了,其他这样的情况,可以既保证主线程的一种进程,又能够保证形成一种并发和并行都能持续的状态

比如跑完一圈 A, B, C 之后任何一个都没执行完,那么就在回到 A 执行一次。由于把 A 的栈保存在了 HEAP 里,此时就可以把A的栈复制粘贴会系统栈里(其实真实情况不是这样的,会意即可),然后再调用 A,这时候由于 A 是跑到一半自己说跳出来的,所以会从刚刚跳出来的地方继续执行。

image.png

图中看,有2个物理线程 M,每一个 M 都拥有一个 context(P),每一个也都有一个正在运行的 goroutine。
P 的数量可以通过 GOMAXPROCS()来设置,其实也就代表了真正的并发度,即有多少个 goroutine 可以同时运行。
图中灰色的那些 goroutine 并没有运行,而是出于 ready 的就绪态,正在等待被调度。P维护着这个队列(称之为 runqueue)
Go 语言里,启动一个 goroutine 很容易: go function  就行,所以每有一个 go 语句被执行,runqueue  队列就在其末尾加入一个
goroutine,在下一个调度点,就从 runqueue 中取出(如何决定取哪个 goroutine ? )一个 goroutine 执行。
为何要维护多个上下文 P?因为当一个 0s 线程被阻塞时,P 可以转而投奔另一个 OS 线程!
图中看到,当一个 0S 线程 MO 陷入阻塞时,P 转而在 os 线程M1I上运行。调度器保证有足够的线程来运行所以的 context P。

相关文章
|
编解码 算法 安全
【总结整理】【路径规划】- 浅谈路径规划算法
# 0 序 本文将从两个大块浅谈一下路径规划算法,第一部分是规划算法本身,第二部分是地图。 ---- howe # 1 前言   移动一个简单的物体(object)看起来很容易,而路径搜索却比较复杂。那为什么涉及到路径搜索就产生麻烦了呢?考虑以下情况: ![image.png](https://ata2-img.oss-cn-zhangjiakou.aliyuncs.com/
20670 4
【总结整理】【路径规划】- 浅谈路径规划算法
|
传感器
STM32:红外传感器代码部分(内含实物图+外部信号流程,编写代码思路+代码+解析代码和扩展应用)
STM32:红外传感器代码部分(内含实物图+外部信号流程,编写代码思路+代码+解析代码和扩展应用)
5063 1
STM32:红外传感器代码部分(内含实物图+外部信号流程,编写代码思路+代码+解析代码和扩展应用)
|
缓存 自动驾驶 物联网
C-RAN——无线接入网架构优化 | 带你读《5G时代的承载网》之十八
C-RAN 是根据现网条件和技术进步的趋势,提出的新型无线接入网构架, 是基于集中化处理(Centralized Processing)、协作式无线电(Collaborative Radio)和实时云计算构架(Real-time Cloud Infrastructure)的绿色无线接 入网构架(Clean System)。其本质是通过实现减少基站机房数量,减少能耗, 采用协作化、虚拟化技术,实现资源共享和动态调度,提高频谱效率,以达到 低成本、高带宽和灵活度的运营。
C-RAN——无线接入网架构优化 | 带你读《5G时代的承载网》之十八
|
Docker Windows 容器
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
3433 1
解决 windows:An attempt was made to access a socket in a way forbidden by its access permissions
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之如何创建mysql临时表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
机器学习/深度学习 人工智能 资源调度
【博士每天一篇文献-算法】连续学习算法之HAT: Overcoming catastrophic forgetting with hard attention to the task
本文介绍了一种名为Hard Attention to the Task (HAT)的连续学习算法,通过学习几乎二值的注意力向量来克服灾难性遗忘问题,同时不影响当前任务的学习,并通过实验验证了其在减少遗忘方面的有效性。
240 12
|
安全 Linux 数据安全/隐私保护
探索Linux命令newuidmap:用户ID映射的利器
`newuidmap`是Linux工具,用于在用户命名空间中设定UID映射,支持容器安全。它允许限定容器内进程的主机系统权限,确保数据安全和隔离。通过映射文件或命令行参数定义UID映射,提供灵活性和安全性。例如,为Docker容器设置映射,使进程能访问特定UID的数据文件。使用时需注意映射准确性、权限控制和避免映射过多UID。与其他工具如`newgidmap`配合使用以增强用户命名空间支持。
|
安全 Java 程序员
阿里开发手册 嵩山版-编程规约 (四)OOP规约-Java程序员必看知识点!!!
《阿里开发手册 嵩山版》的OOP规约部分强调了面向对象编程的最佳实践,包括正确使用静态方法、覆写方法的注解、可变参数的使用、接口的稳定性、equals和compareTo方法的使用、BigDecimal的正确比较、包装类与基本数据类型选择、POJO类的属性和方法设计等,以提升代码的质量和维护性。
|
存储 缓存 小程序
【微信小程序3】本地缓存:一次性存储多个对象值
【微信小程序3】本地缓存:一次性存储多个对象值
312 0
|
监控 负载均衡 算法
Golang深入浅出之-Go语言中的协程池设计与实现
【5月更文挑战第3天】本文探讨了Go语言中的协程池设计,用于管理goroutine并优化并发性能。协程池通过限制同时运行的goroutine数量防止资源耗尽,包括任务队列和工作协程两部分。基本实现思路涉及使用channel作为任务队列,固定数量的工作协程处理任务。文章还列举了一个简单的协程池实现示例,并讨论了常见问题如任务队列溢出、协程泄露和任务调度不均,提出了解决方案。通过合理设置缓冲区大小、确保资源释放、优化任务调度以及监控与调试,可以避免这些问题,提升系统性能和稳定性。
539 6