Go Runtime
1. goroutine定义
golang在语言级别支持协程,称之为goroutine
都会让出CPU给其它goroutine, 这让goroutine的切换管理不依赖于系统的线程和进程,也不依赖于CPU的核心数量
而是交给Golang的运行时统一调度
2. GMP指的是什么
* G(goroutine),我们所说的协程,用户级的轻量级线程,每个goroutine对象中的sched保存着其上下文信息
* M(machine),对内核级线程的封装,数量对应真实的CPU数量(真正干活的对象)
* P(processor),即为G和M的调度对象,用来调度G和M之间的关联关系,其数量可通过GOMAXPROCS来设置,默认是CPU核心数量
3. 1.0之前GM调度模型
调度器把不同的G分配到M上,不同的G在不同的M并发运行时,都需要向系统申请资源,比如堆栈内存,因为资源是全局的
就会因为资源竞争造成很多性能损耗,为了解决这一问题go从1.1版本引入,在运行时系统的时候加入p对象,
让P去管理G对象,M想要运行G,必须先绑定P,然后才能运行P下面的G对象
GM调度存在的问题:
1. 单一全局互斥锁(Sched.Lock)和集中状态存储
2. groutine传递问题(M经常在M之间传递可运行的goroutine)
3. 每个M做内存缓存,导致内存占用过高,数据局部性较差
4. 频繁的syscall调用, 导致严重的线程阻塞/解锁,家具额外的性能损耗_
4. GMP调度流程
1. 每个p有个局部队列,局部队列放的是待执行的goroutine,当M绑定的P的局部队列满了以后就会把G放到全局队列
2. 每个P和一个M绑定,M是真正执行P中goroutine的实体,M从绑定的P的局部队列中获取G来执行
3. 当M绑定的P的局部队列为空时,M就会从全局队列获取到本地队列来执行,当全局队列也为空时,
M就会从其它P队列偷取G来执行,这种从其它P偷的方式称之为 work stealing
4. 当G因系统调用(syscall)阻塞时会阻塞M,此时P会和M解绑即hand off,并寻找新的M,如果没有空闲的M就会新建一个M
5. 当G因channel或者network I/O操作阻塞时,不会阻塞M,M会寻找其它runable的G,当阻塞的G恢复后重新进入runable进入P队列等待执行
5. GMP中的work stealing机制
先获取p本地队列,如果为空时,去全局队列里取G运行,如果全局队列为空时从netpoll和事件池里拿
如果在拿不到从其它P队列里偷
6. GMP中的handoff机制
当本地线程M因为G进行的系统调用阻塞时,会释放绑定的P,把P转移给其它空闲的M执行
7. 协作式的抢占式调度
在1.14之前,程序只能依靠goroutine主动让出CPU资源才能触发调用,这种方式存在问题有:
1. goroutine长时间占用线程,造成其它goroutine的饥饿
2. 垃圾回收需要暂停整个程序,最长可能几分钟,导致整个程序无法工作
8. 基于信号的抢占式调度
1. 在任何情况下,go运行时并行执行的goroutine数量要小于等于p的数量
2. 为了提高性能,p的数量肯定不是越小越好,官方给出默认是CPU的核心数量
3. 如果设置过小的,当M绑定的P执行的G执行系统调用阻塞,导致M也阻塞时,GO的调度器是迟钝的,他有可能什么都不做
它有可能什么都不做,知道M阻塞了相当长时间以后,才会发现一个P/M被syscall阻塞了,然后才会用空闲的M来抢这个P
所以P也不建议设置太小,通过sysmon监控实现的抢占式调度,最快在20us,最慢在10-20ms才会发现一个M持有P并阻塞了,
而操作系统1ms可以完成几十次系统调度
所以P适当的比CPU核心数多一些最好
9. GMP调度过程中存在哪些阻塞
1. I/O, select
2. block on syscall
3. channel
4. 等待所
5. runtime.Gosched()
10. sysmon有什么用
sysmon也叫监控线程,变动的周期性检查,好处
1. 释放超过5分钟的span物理内存
2. 如果超过两分钟没有垃圾回收,强制执行
3. 将长时间未处理的netpoll加入到全局队列
4. 向长时间运行的g任务发出抢占调度(超过10ms的g,会进行retake)
5. 收回因syscall阻塞的P
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)