【golang】深入理解GMP调度模型

您所在的位置:网站首页 gmp是指什么体系的运行机制 【golang】深入理解GMP调度模型

【golang】深入理解GMP调度模型

2024-07-13 20:50:42| 来源: 网络整理| 查看: 265

Goroutine

Go中,协程被称为goroutine,它非常轻量,一个goroutine只占几KB,并且这几KB就足够goroutine运行完,这就能在有限的内存空间内支持大量goroutine,支持了更多的并发,虽然一个goroutine的栈只占几KB(Go语言官方说明为4~5KB),但实际是可伸缩的,如果需要更多内容,runtime会自动为goroutine分配。

Goroutine特点:

占用内存更小(几kb)调度更灵活(runtime调度) GMP指的是什么

G(Goroutine):我们在Go语言中所说的协程,为用户级的轻量级线程,每个Goroutine对象中的sched保存着其上下文信息。 M(Machine):对内核级线程的封装,数量对应真实的CPU数(真正干活的对象,默认最大数量为10000)。 P(Processor):即为G和M的调度对象,用来调度G和M之间的关联关系,其数量可通过,GOMAXPROCS()来设置,默认为核心数。

版本1.0之前GM调度模型

调度器把G都分配M上,不同的G在不同的M并发运行时,都需要向系统申请资源,比如堆栈内存等,因为资源是全局的,就会因为资源竞争造成很多性能损耗。为了解决这样的问题go从1.1版本引入,在运行时系统的时候加入p对象,让P去管理这个G对象,M想要运行G,必须绑定P,才能运行P所管理的G。

在这里插入图片描述

GM调度存在的问题:

单一全局互斥锁(SchedLock)和集中状态存储Goroutine传递问题(M经常在M之间传递“可运行”的goroutine)每个M作内存缓存,导致内存占用过高,数据局部性较差频繁syscall调用,导致严重的线程阻塞/解锁,加剧的性能损耗。 GMP模型

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

在这里插入图片描述

全局队列:存放等待运行的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的核上执行。

go func()调度流程

在这里插入图片描述 流程:

通过go func() 来创建一个goroutine;有两个存储G的队列,一个是局部调度器P的本地队列、一个是全局G队列。新创建的G会先保存在P的本地队列中,如果P的本地队列已经满了就会保存在全局的队列中;G只能运行在M中,一个M必须持有一个P,M与P是1:1的关系。M会从P的本地队列弹出一个可执行状态的G来执行,如果P的本地队列为空,就会想其他的MP组合偷取一个可执行的G来执行。一个M调度G执行的过程是一个循环机制;当M执行某一个G时候如果发生了syscall或者其余阻塞操作,M会阻塞,如果当前有一些G在执行,runtime会把这个线程M从P中摘除(detach),然后再创建一个新的操作系统的线程(如果有空闲的线程可用就复用空闲线程)来服务于这个P;当M系统调用结束时候,这个G会尝试获取一个空闲的P执行,并放入到这个P的本地队列,如果获取不到P,那么这个线程M变成休眠状态,加入到空闲线程中,然后这个G会被放入全局队列中。

M0 M0是启动程序后的编号为0的主线程,这个M对应的实例会在全局变量runtime.m0中,不需要在heap上分配,M0负责执行初始化操作和启动第一个G,在之后M0就和其他的M一样了。 G0 G0是每次启动一个M都会第一个创建的gourtine,G0仅用于负责调度的G,G0不指向任何可执行的函数,每个M都会有一个自己的G0。在调度或系统调用时会使用G0的栈空间,全局变量的G0是M0的G0;

调度器的设计策略 复用线程

避免频繁的创建、销毁线程,而是对线程的复用。

work stealing机制:获取 P 本地队列,当从绑定 P 本地 runq 上找不到可执行的 g,尝试从全局链表中拿,再拿不到从 netpoll 和事件池里拿,最后会从别的 P 里偷任务。hand off机制:当本线程M因为G进行的系统调用阻塞时,线程释放绑定的P,把P转移给其他空闲的M执行。 利用并行

GOMAXPROCS设置P的数量,最多有GOMAXPROCS个线程分布在多个CPU上同时运行。GOMAXPROCS也限制了并发的程度,比如GOMAXPROCS = 核数/2,则最多利用了一般的CPU和进行并行。

抢占

在go版本1.2-1.13是基于协作的抢占式调度,只能依靠goroutine主动让出CPU资源才能触发调度,在1.14及以后的版本后,golang实现了基于信号的抢占式调度,一个goroutine最多占用 CPU 10ms,防止其他goroutine被饿死。

全局G队列

在新的调度器中依然有全局G队列,但功能被弱化了,当M执行work stealing从其他P偷不到G时,它可以从全局G队列获取G。

版本1.2 ~ 1.13 基于协作的抢占式调度

版本1.2~1.13,程序只能依靠Goroutine主动让出CPU资源才能触发调度。

问题:

某些Goroutine可以长时间占用线程,造成其它Goroutine的饥饿垃圾回收需要暂停整个程序(Stop-the-world,STW),最长可能需要几分钟的时间,导致整个程序无法工作。 版本1.14~至今 基于信号的抢占式调度

在任何情况下,Go 运行时并行执行(注意,不是并发)的 goroutines 数量是小于等于 P 的数量的。为了提高系统的性能,P 的数量肯定不是越小越好,所以官方默认值就是 CPU 的核心数,设置的过小的话,如果一个持有 P 的 M, 由于 P 当前执行的 G 调用了 syscall 而导致 M 被阻塞,那么此时关键点: GO 的调度器是迟钝的,它很可能什么都没做,直到 M 阻塞了相当长时间以后,才会发现有一个 P/M 被 syscall 阻塞了。然后,才会用空闲的 M 来强这个P。通过 sysmon 监控实现的抢占式调度,最快在 20us,最慢在10-20ms才会发现有一个 M 持有 P 并阻塞了。操作系统在 1ms 内可以完成很多次线程调度(一般情况1ms 可以完成几十次线程调度),Go 发起 IO/syscall 的时候执行该 G 的 M会阻塞然后被 OS 调度走,P 什么也不干,sysmon 最慢要10-20ms才能发现这个阻塞,说不定那时候阻塞已经结束了,这样宝贵的 P 资源就这么被阻塞的M 浪费了。

Sysmon 有什么作用?

Sysmon 也叫监控线程,会变动的周期性检查

好处:

释放闲置超过 5 分钟的 span 物理内存;如果超过 2 分钟没有垃圾回收,强制执行;将长时间未处理的 netpoll 添加到全局队列;向长时间运行的 G 任务发出抢占调度(超过10ms的g,会进行retake);收回因 syscall 长时间阻塞的 P; GMP调度过程中存在哪些阻塞 I/O,selectblock on syscall(系统调用(syscall)过程中发生了阻塞)channel等待锁runtime.Gosched()(手动让当前 Goroutine 主动让出执行权)


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭