一文理解Goland协程调度器scheduler的实现

目录
  • 1. 调度器scheduler的作用
  • 2. GMP模型
  • 3. 调度机制

1. 调度器scheduler的作用

我们都知道,在Go语言中,程序运行的最小单元是gorouines。

然而程序的运行最终都是要交给操作系统来执行的,以Java为例,Java中的一个线程对应的就是操作系统中的线程,以此来实现在操作系统中的运行。在Go中,gorouines比线程更轻量级,其与操作系统的线程也不是一一对应的关系,然而,最终我们想要执行程序,还是要借助操作系统的线程来完成,调度器scheduler的工作就是完成gorouines到操作系统线程的调度。

2. GMP模型

当我们运行go fun(){}时,会生成一个g,优先放置在创建他的p的本地队列中,如果本地队列已满,那么会放置在全局队列中。

g的运行需要借助p与m,p是执行器,只有获得p的g才能执行,p的执行需要挂在m上,m对应的是操作系统中的线程,p的数量与CPU的核数相同。

goroutine运行所需要的上下文信息都是存放在g的数据结构当中的,所以g可以依靠任意的p或者m执行,而对于操作系统而言,其并不能看到p与g的调度过程,这些过程对于操作系统线程来说都是连续的,所以省去了线程上下文切换的开销。

g的数据结构如下所示:

type g struct {
    stack       stack   // g自己的栈

    m            *m      // 执行当前g的m
    sched        gobuf   // 保存了g的现场,goroutine切换时通过它来恢复
    atomicstatus uint32  // g的状态Gidle,Grunnable,Grunning,Gsyscall,Gwaiting,Gdead
    goid         int64
    schedlink    guintptr // 下一个g, g链表

    preempt       bool //抢占标记

    lockedm        muintptr // 锁定的M,g中断恢复指定M执行
    gopc           uintptr  // 创建该goroutine的指令地址
    startpc        uintptr  // goroutine 函数的指令地址
}

p的数据结构如下所示:

type p struct {
    id          int32
    status      uint32 // 状态
    link        puintptr // 下一个P, P链表
    m           muintptr // 拥有这个P的M
    mcache      *mcache  

    // P本地runnable状态的G队列
    runqhead uint32
    runqtail uint32
    runq     [256]guintptr

    runnext guintptr // 一个比runq优先级更高的runnable G

    // 状态为dead的G链表,在获取G时会从这里面获取
    gFree struct {
        gList
        n int32
    }

    gcBgMarkWorker       guintptr // (atomic)
    gcw gcWork

}

m的数据结构如下所示:

type m struct {
    g0      *g     // g0, 每个M都有自己独有的g0

    curg          *g       // 当前正在运行的g
    p             puintptr // 当前用于的p
    nextp         puintptr // 当m被唤醒时,首先拥有这个p
    id            int64
    spinning      bool // 是否处于自旋

    park          note
    alllink       *m // on allm
    schedlink     muintptr // 下一个m, m链表
    mcache        *mcache  // 内存分配
    lockedg       guintptr // 和 G 的lockedm对应
    freelink      *m // on sched.freem

} 

通过gmp模型,我们能解决gorouines到操作系统线程的映射问题,gorouines之间的切换是在用户态完成的,在操作系统的视角来看,线程的上下文切换并不频繁,因此就少了很多陷入内核的过程,所以有更好的并发效果。

3. 调度机制

1)work stealing机制

当一个p上的g执行完之后,他会尝试从其他的p队列中窃取g来执行,以减少操作系统线程的切换动作。

2)hand off机制

这个是针对m来说的,有的时候m可能因为g的信号调用而被操作系统阻塞,这个时候p就会挂载去另一个m继续执行可以执行的g,当阻塞的m就绪之后,会给p发信号,召唤他回来继续进行后续操作。

到此这篇关于一文理解Goland协程调度器scheduler的实现的文章就介绍到这了,更多相关Goland协程调度器scheduler内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • django使用django-apscheduler 实现定时任务的例子

    下载: pip install apscheduler pip install django-apscheduler 将 django-apscheduler 加到项目中settings的INSTALLED_APPS中 INSTALLED_APPS = [ .... 'django_apscheduler', ] 然后迁移文件后 ./manage.py migrate 生成两个表:django_apscheduler_djangojob 和 django_apscheduler_djangojo

  • 在django-xadmin中APScheduler的启动初始化实例

    环境: python3.5.x + django1.9.x + xadmin-for-python3 APScheduler做为一个轻量级和使用量很多的后台任务计划(scheduler)包,可以方便的随系统启动/关闭而启动/关闭,如果整合到django中,启动APScheduler的代码该写在哪里好呢, 以下几个方式供参考: 1. (推荐)自定义Middleware,非常类似Java中的Filter,缺点是要有URL访问才会触发启动,如果系统还没有启动完就访问了URL会触发__init__多次调

  • 在django中使用apscheduler 执行计划任务的实现方法

    对于任何软件开发人员而言,为将来计划任务都是必不可少的工具. 尽管我们创建的许多编程旨在响应明确的触发或用户事件,但定期执行的后台进程也同样重要. "每个星期一早晨更新结果." "每天晚上分批下单." 甚至具有每日请求限制的第三方API也隐式要求这种行为. "我们只能每五分钟请求一次更新." 幸运的是,许多聪明的人已经解决了这个问题,并且不难找到python本地解决方案. Advanced Python Scheduler(APS)是一个很好的选

  • 一文理解Goland协程调度器scheduler的实现

    目录 1. 调度器scheduler的作用 2. GMP模型 3. 调度机制 1. 调度器scheduler的作用 我们都知道,在Go语言中,程序运行的最小单元是gorouines. 然而程序的运行最终都是要交给操作系统来执行的,以Java为例,Java中的一个线程对应的就是操作系统中的线程,以此来实现在操作系统中的运行.在Go中,gorouines比线程更轻量级,其与操作系统的线程也不是一一对应的关系,然而,最终我们想要执行程序,还是要借助操作系统的线程来完成,调度器scheduler的工作就

  • 一文详解Golang协程调度器scheduler

    目录 1. 调度器scheduler的作用 2. GMP模型 3. 调度机制 1. 调度器scheduler的作用 我们都知道,在Go语言中,程序运行的最小单元是gorouines. 然而程序的运行最终都是要交给操作系统来执行的,以Java为例,Java中的一个线程对应的就是操作系统中的线程,以此来实现在操作系统中的运行.在Go中,gorouines比线程更轻量级,其与操作系统的线程也不是一一对应的关系,然而,最终我们想要执行程序,还是要借助操作系统的线程来完成,调度器scheduler的工作就

  • 深入理解python协程

    一.什么是协程 协程拥有自己的寄存器和栈.协程调度切换的时候,将寄存器上下文和栈都保存到其他地方,在切换回来的时候,恢复到先前保存的寄存器上下文和栈,因此:协程能保留上一次调用状态,每次过程重入时,就相当于进入上一次调用的状态. 协程的好处: 1.无需线程上下文切换的开销(还是单线程) 2.无需原子操作(一个线程改一个变量,改一个变量的过程就可以称为原子操作)的锁定和同步的开销 3.方便切换控制流,简化编程模型 4.高并发+高扩展+低成本:一个cpu支持上万的协程都没有问题,适合用于高并发处理

  • Vue3生命周期Hooks原理与调度器Scheduler关系

    目录 写在最前:本文章的目标 Vue3生命周期的实现原理 生命周期类型 各个生命周期Hooks函数的创建 创建生命周期函数createHook injectHook函数 生命周期Hooks的调用 Vue3调度器(Scheduler)原理 Vue父子组件的生命周期的执行顺序 父子组件的执行顺序 父子组件生命周期的执行顺序 组件卸载的时候,是在卸载些什么呢? 组件更新的调度器里的队列任务的失效与删除的区别 父子组件执行顺序与调度器的关系 Hooks的本质 最后 写在最前:本文章的目标 Vue3的生命

  • Go 并发编程协程及调度机制详情

    目录 协程的概念 goroutine 的诞生 使用 goroutine 加快速度 goroutine 的机制原理 前言: 协程(coroutine)是 Go 语言最大的特色之一,goroutine 的实现其实是通过协程. 协程的概念 协程一词最早出现在 1963 年发表的论文中,该论文的作者为美国计算机科学家 Melvin E.Conway.著名的康威定律:“设计系统的架构受制于产生这些设计的组织的沟通结构.” 也是这个作者. 协程是一种用户态的轻量级线程,可以想成一个线程里面可以有多个协程,而

  • 详细解读tornado协程(coroutine)原理

    tornado中的协程是如何工作的 协程定义 Coroutines are computer program components that generalize subroutines for nonpreemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.. -- [ 维基百科 ] 我们在平常编程中,更习惯使用的是子

  • Kotlin协程概念原理与使用万字梳理

    目录 一.协程概述 1.概念 2.特点 3.原理 二.协程基础 1.协程的上下文 2.协程的作用域 3.协程调度器 4.协程的启动模式 5.协程的生命周期 三.协程使用 1.协程的启动 2.协程间通信 3.多路复用 4.序列生成器 5.协程异步流 6.全局上下文 一.协程概述 1.概念 协程是Coroutine的中文简称,co表示协同.协作,routine表示程序.协程可以理解为多个互相协作的程序.协程是轻量级的线程,它的轻量体现在启动和切换,协程的启动不需要申请额外的堆栈空间:协程的切换发生在

  • Java 协程 Quasar详解

    目录 前言 协程是什么? Quasar使用 1.运行时间 2.内存占用 3.原理与应用 总结 前言 在编程语言的这个圈子里,各种语言之间的对比似乎就一直就没有停过,像什么古早时期的"PHP是世界上最好的语言"就不提了,最近我在摸鱼的时候,看到不少文章都在说"Golang性能吊打Java".作为一个写了好几年java的javaer,这我怎么能忍?于是在网上看了一些对比golang和java的文章,其中戳中java痛点.也是golang被吹上天的一条,就是对多线程并发的

  • Kotlin协程的基础与使用示例详解

    目录 一.协程概述 1.概念 2.特点 3.原理 1)续体传递 2)状态机 二.协程基础 1.协程的上下文 2.协程的作用域 3.协程调度器 4.协程的启动模式 5.协程的生命周期 1)协程状态的转换 2)状态标识的变化 三.协程使用 1.协程的启动 1)runBlocking方法 2)launch方法 3)async方法 4)suspend关键字 5)withContext方法 6)suspend方法 2.协程间通信 1)Channel 2)Channel的容量 3)produce方法与act

  • Kotlin图文并茂讲解续体与续体拦截器和调度器

    目录 一.Continuation 二.ContinuationInterceptor 三.CoroutineDispatcher 四.EventLoop 一.Continuation Continuation接口是协程中最核心的接口,代表着挂起点之后的续体,代码如下: public interface Continuation<in T> { // 续体的上下文 public val context: CoroutineContext // 该方法用于恢复续体的执行 // result为挂起

随机推荐