首页 > 其他分享 >Golang抢占式调度

Golang抢占式调度

时间:2022-12-04 17:47:39浏览次数:35  
标签:goroutine 抢占 Goroutine 式调度 Golang 线程 runtime

Golang抢占式调度

在1.12版本之前,go的调度器不支持抢占式调度,程序只能依靠Goroutine主动让出CPU资源才能触发调度,会引发一些问题,如

  • 某些Goroutine可以长时间占用线程,造成其它 Goroutine的饥饿
  • 垃圾回收器是需要stop the world的。如果垃圾回收器想要运行了,那么它必须先通知其它的goroutine合作停下来,这会造成较长时间的等待时间。

基于协作的抢占式调度

Goroutine引入了stackguard0字段,当该字段设置为StackPreempt意味着当前Goroutine发出了抢占请求;同时在runtime.newstack:1e112cd中增加抢占的代码,当stackguard0等于StackPreempt时触发调度器抢占让出线程。

gorogoutine创建之初,栈的大小是固定的,为了防止栈溢出,编译器会在有明显栈消耗的函数头部插入一些检测代码,通过stackguard0值来决定是否触发runtime.morestack函数。将stackguard0设置为StackPreempt作用是进入函数时必定触发runtime.morestack,然后在调用runtime.newstack。

工作机制

  • 编译器会在调用函数前插入runtime.morestack,可能会调用runtime.newstack进行抢占
  • Go语言运行时会在垃圾回收暂停程序、系统监控发现Goroutine运行超过10ms时发出抢占请求StackPreempt
  • 当发生函数调用时,可能会执行编译器插入的runtime.morestack,它调用的runtime.newstack会检查Goroutine的stackguard0字段是否为 StackPreempt;
  • 如果stackguard0是StackPreempt,就会触发抢占让出当前线程;

但是这种调度并不完备,比如一个goroutine运行了很久,但是它并没有调用另一个函数,则它不会被抢占。

基于信号的抢占式调度

在之前的依赖栈增长检测代码的方式,遇到没有函数调用的情况下就会出现问题,在Go1.14这一问题得到解决。
在Linux中这种真正的抢占式调度是基于信号完成的,所以也称为“异步抢占”。

工作机制

  • M注册一个SIGURG信号的处理函数:sighandler。
  • sysmon线程检测到执行时间过长的goroutine或者GC stw时,会向相应的M(或者说线程,每个线程对应一个 M)发送SIGURG信号。
  • 收到信号后,内核执行sighandler函数,通过pushCall插入asyncPreempt函数调用。
  • 回到当前goroutine执行asyncPreempt函数,通过mcall切到g0栈执行gopreempt_m。
  • 将当前goroutine插入到全局可运行队列,M则继续寻找其他goroutine来运行。
  • 被抢占的goroutine再次调度过来执行时,会继续原来的执行流。

基于信号的抢占式调度,抢占也只会在垃圾回收扫描任务时触发。

标签:goroutine,抢占,Goroutine,式调度,Golang,线程,runtime
From: https://www.cnblogs.com/JevonWei/p/16950257.html

相关文章

  • Golang 协程调度器原理及GPM模型
    目录进程和线程内核级线程用户级线程协程协程与线程的关系N:11:1M:Ngoroutine旧版本goroutine调度器调度器的实现Goroutine调度器的GMP模型设计思想GPM结构组成GPM运行模型......
  • golang的希尔排序
    1、什么是希尔排序:插入排序的一种又称“缩小增量排序”(DiminishingIncrementSort),是直接插入排序算法​的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.......
  • Golang文件服务器
    主调函数,设置路由表packagemainimport( "fmt" "net/http" "store/handler")funcmain(){ http.HandleFunc("/file/upload",handler.UploadHandler) http.Ha......
  • Golang反射获得变量类型和值
    1.什么是反射反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。Golang反射包中有两对非常重要的函数和类型,两个函数分别是:reflect.TypeOf能获取类......
  • golang rang 字符串
    golang遍历字符串,有多种方式:``点击查看代码 //字符串,把字符串起来 s:="中国人,zgr" forpos,char:=ranges{ //range是按照字符来遍历,返回字符出现的位置......
  • golang的单引号、双引号、反引号区别
    1、单引号在go语言中表示golang中的rune(int32)类型,byte(int8别称),单引号里面是单个字符,对应的值为改字符的ASCII值。Unicode是ASCII(美国信息交换标准码)字符编码的一个扩展......
  • Go-07 Golang中的数组
    packagemainimport"fmt"/*...Golang中的数组...*//* Go语言中的数组是指一系列相同类型数据的集合。数组中的元素必须要相同数据类型。数组中包含的每个数据被称......
  • golang gorm使用
     gorm链式操作:MethodChaining,Gorm实现了链式操作接口,所以你可以把代码写成这样: //创建一个查询tx:=db.Where("name=?","jinzhu")//添加更多条件ifso......
  • golang的插入排序算法
    1、什么是插入排序?先看一个例子:{7,6,1,9,3}无序数列中,我们约定好无序数列的第一个元素7作为有序数列{7},然后分别对{6,1,9,3}的数与7进行比较移位得到新的有序数列。第一次迭......
  • golang校验结构体字段的库validator的使用
    packagescripts_stroageimport("fmt""github.com/go-playground/validator/v10""testing")//参考博客://https://juejin.cn/post/69003756803582......