什么是GO语言里面的GMP调度模型?

![https://www.yuque.com/aceld/golang/srxd6d

图片\]](https://i-blog.csdnimg.cn/direct/56b140d6fed04eb2a63b425b8d007fce.png) GMP是Go语言的协程调度模型,G代表goroutine,M代表内核线程,P代表逻辑处理器,P中包含本地运行的G队列,G通过P绑定到M上才能运行。 注:协程会给你上下文切换保存了那些寄存器?发生调度的时机? * rsp:指向函数调用的栈顶。 * rip:指向程序要执行的下一条指令地址。 * rbp:存储函数栈帧的起始地址。 重点:GMP的调度流程 调度时机 * 等待读取channel或者是写入无缓冲的channel * 使用time.Sleep睡眠 * 等待互斥量执行完毕释放的过程 * 发生了系统调用,如文件读写、网络请求等 调度流程 协程在刚创建的时候,会优先加入到当前P的本地队列中,去等待调度,如果这个P队列满了,会将一半的G和这个新创建的G打乱顺序一起放入全局队列中。每个M都有一个特殊的协程g0负责调度工作,每一轮的调度,M都是优先去执行与它绑定的P的本地队列上的G,如果本地队列中没有G,就会从全局队列获取,若全局队列也没有,就会从其它P的队列中偷取一半的G,如果这也没有获取到的话,就会让M进入自旋状态。 以上就是GMP的调度流程,但是可能会出现几个问题: 1、如果说P本地队列一直有G呢?那么全局队列怎么办? 不用担心,Go的调度器每执行61次之后,就会优先从全局队列中获取一个G放到当前P本地队列中。 调度方式 分为两种,协作式和抢占式。 在Go1.14之前,是协作式抢占的,Go会启动一个线程,一直运行着sysmon函数,当sysmon发现M已运行同一个G10ms以上时,它会将G的内部参数preempt设置为true,当G进行函数调用的时候,会判断preempt,如果为true,则将这个G和M分离,并将G放入全局队列中。(注意:发生函数调用之后,才能判断preempt) 在Go1.14之后,是基于信号的异步抢占。sysmon会检测运行了10ms以上的G,然后,sysmon向运行G的M发送信号,Go的信号处理程序会调用M上一个叫做gsignal 的goroutine来处理该信号,若gsignal看到抢占信号,就停止正在运行的G,并将G放入到全局队列中。这一种基于信号量的抢占可以防止类似死循环的这种,没有发生函数调用的goroutine一直占用cpu导致程序阻塞。 GMP能不能去掉P层?会怎么样呢?M和P的数量? 不能去掉P层。因为早期的就是GM模型,没有P的本地队列,那么每次所有的M都要去全局队列中获取可用的G,这样会造成大量的锁竞争问题。而有了P层之后,大幅度减轻了对全局队列的直接依赖,让锁竞争问题大大减少,并且在GMP中也实现了work stealing算法,若P的本地队列为空,就会从全局队列或其它的P本地队列中来偷取可用的G来运行,提高了资源利用率,所以不能去掉P层。 进程、线程、协程? * 进程是操作系统分配资源的基本单位,而线程是操作系统调度的基本单位,进程独占一个虚拟内存空间,而进程里的线程共享一个进程虚拟内存空间。

相关推荐
回家路上绕了弯2 分钟前
分布式系统重试策略详解:可靠性与资源消耗的平衡艺术
分布式·后端
王中阳Go3 分钟前
别再卷 Python 了!Go + 字节 Eino 框架,才是后端人转 AI 的降维打击(附源码)
后端·面试·go
superman超哥7 分钟前
Rust 表达式与语句的区别:函数式思维与控制流设计
开发语言·后端·rust·rust表达式·rust语句·函数式思维·控制流设计
fliter8 分钟前
常见的链上攻击向量
后端
趁月色小酌***11 分钟前
JAVA 知识点总结5
java·开发语言·python
caesar_lion15 分钟前
C++ 多线程陷阱:分离线程(detached thread)访问已析构对象的致命隐患
后端
Macbethad15 分钟前
SpringMVC RESTful API开发技术报告
java·spring boot·后端
05大叔15 分钟前
SpringMVCDay01
java·开发语言
代码游侠18 分钟前
复习——网络测试工具
linux·开发语言·网络·笔记·学习·测试工具
青梅主码18 分钟前
OpenAI最新发布年度重磅报告《2025年企业人工智能状况报告》:ChatGPT企业版消息量同比增长约8倍
后端