内存由大量内存单元组成,内存单元大小为1个字节(1字节包含8个二进制位), 每个内存单元都有一个编号,更专业的说法是每一个内存单元都有一个地址,我们在编写汇编代码或编译器把用高级语言所写的程序编译成汇编指令时...下面再用上一节讨论寄存器时使用过的例子来帮助我们加深对内存的理解: c = a + b // go语言代码 mov (%rsp),%rdx #把变量a的值从内存中读取到寄存器rdx...中 mov 0x8(%rsp),%rax #把变量b的值从内存中读取到寄存器rax中 add %rdx,%rax #把寄存器rdx和rax中的值相加,并把结果放回rax...寄存器中 mov %rax,0x10(%rsp) #把寄存器rax中的值写回变量c所在的内存 这里的4条指令有3条跟内存读写有关,指令中的rsp寄存器里面存放的是一个内存地址,现假设这个内存地址是...X, 则第一条指令 mov (%rsp),%rdx 表示把从地址为X开始的8个内存单元中的值读取到rdx寄存器中(因为rdx是一个64位寄存器,这就隐含了要一次读取连续的8个字节,指令中的地址只是起始地址
本文是《go调度器源代码情景分析》系列 第一章 预备知识的第九小节。...要深入理解goroutine的调度器,就需要对操作系统线程有个大致的了解,因为go的调度系统是建立在操作系统线程之上的,所以接下来我们对其做一个简单的介绍。...如上所述,操作系统会把不同的线程调度到同一个CPU上运行,而每个线程运行时又都会使用CPU的寄存器,但每个CPU却只有一组寄存器,所以操作系统在把线程B调度到CPU上运行时需要首先把刚刚正在运行的线程A...线程调度时操作系统需要保存和恢复的寄存器除了通用寄存器之外,还包括指令指针寄存器rip以及与栈相关的栈顶寄存器rsp和栈基址寄存器rbp,rip寄存器决定了线程下一条需要执行的指令,2个栈寄存器确定了线程执行时需要使用的栈内存...所以恢复CPU寄存器的值就相当于改变了CPU下一条需要执行的指令,同时也切换了函数调用栈,因此从调度器的角度来说,线程至少包含以下3个重要内容: 一组通用寄存器的值 将要执行的下一条指令的地址 栈 所以操作系统对线程的调度可以简单的理解为内核调度器对不同线程所使用的寄存器和栈的切换
CPU对这16个通用寄存器的用途没有做特殊规定,程序员和编译器可以自定义其用途(下面会介绍,rsp/rbp寄存器其实是有特殊用途的); 程序计数寄存器(PC寄存器,有时也叫IP寄存器):rip寄存器。...它用来存放下一条即将执行的指令的地址,这个寄存器决定了程序的执行流程; 段寄存器:fs和gs寄存器。...一般用它来实现线程本地存储(TLS),比如AMD64 linux平台下go语言和pthread都使用fs寄存器来实现系统线程的TLS,在本章线程本地存储一节和第二章详细分析goroutine调度器的时候我们可以分别看到...32位的寄存器,它使用的是rax寄存器的低32位。...rsp 栈顶寄存器和rbp栈基址寄存器 这两个寄存器都跟函数调用栈有关,其中rsp寄存器一般用来存放函数调用栈的栈顶地址,而rbp寄存器通常用来存放函数的栈帧起始地址,编译器一般使用这两个寄存器加一定偏移的方式来访问函数局部变量或函数参数
我们将在最后一章讨论有关系统调用方面的抢占调度,所以这里有必要对系统调用有个基本的了解。 系统调用是指使用类似函数调用的方式调用操作系统提供的API。...另外,用户代码调用操作系统API也不是根据函数名直接调用,而是需要根据操作系统为每个API提供的一个整型编号来调用,AMD64 Linux平台约定在进行系统调用时使用rax寄存器存放系统调用编号,同时约定使用...openat系统调用 syscall #系统调用指令,进入Linux内核 这里,代码首先把6个参数以及openat这个系统调用的编号267保存在了对应的寄存器中
与高级编程语言一样,汇编语言也是一门完整的计算机编程语言,它所涉及的知识内容也很多,好在我们的主要目标是通过对本小节的学习而有能力去读懂汇编代码,而不是要用汇编语言去写代码,所以本节并不会全面介绍汇编语言...不过,虽然这里的介绍做了精简,但读者大可放心,熟练运用这些知识就足以应付本书将要分析的goroutine调度器中的汇编代码了。...汇编指令格式 因为不同的CPU所支持的机器指令不一样,所以其汇编指令也不同,即使是相同的CPU,不同的汇编工具和平台所使用的汇编指令格式也有些差别,由于本书主要专注于AMD64 Linux平台下的go调度器...)中的寄存器的名字用括号括起来了,表示间接寻址,rsp的值是一个内存地址,这条指令的真实意图是把rax寄存器中的值赋值给rsp寄存器的值(内存地址)对应的内存,rsp寄存器本身的值不会被修改,作为比较,...执行mov %rax, %rsp这条指令之前,rsp寄存器的值是x,rax寄存器的值是y,执行指令之后,rax寄存器的值被复制给了rsp寄存器,所以rsp寄存器的值变成了y,可以看出,采用直接寻址方式时
如果调度器支持就绪状态切换到执行状态,同时支持执行状态切换为就绪状态,就称该调度器为抢占式调度器。...:普通进程的调度策略,使我们task以最低优先级选择CFS调度器来调度运行 SCHED_DEADLINE:限期进程调度策略,使我们task选择Deadline调度器来调度运行 注:stop调度器和DLE-task...调度器,仅使用于内核,用户没有办法进行选择 CFS调度器 完全公平调度算法体现在对待每个进程都是公平的,让每个进程都运行一段相同的时间片,这就是基于时间片轮询调度算法。...const struct sched_class *sched_class; // 表示该进程所属的调度器类 CFS:完全公平调度器。...周期性调度器:根据频率自动调用scheduler_tick函数,根据进程运行时间触发调度 上下文切换:主要做两个事情(切换地址空间、切换寄存器和栈空间) CFS调度器的
本文是《go调度器源代码情景分析》系列 第一章 预备知识的第十小节,也是预备知识的最后一小节。...对于像这种由编译器实现的特性,我们怎么开始研究呢?最快最直接的方法就是使用调试工具来调试程序的运行,这里我们使用gdb来调试。 bobo@ubuntu:~/study/c$ gdb ..../thread 首先在源代码的第20行(对应到源代码中的 g = 100)处下一个断点,然后运行程序,程序停在了断点处,反汇编一下main函数: (gdb) b thread.c:20 Breakpoint...fs段基址是多少,虽然我们可以用gdb命令查看fs寄存器的值,但fs寄存器里面存放的是段选择子(segment selector)而不是该段的起始地址,为了拿到这个基地址,我们需要加一点代码来获取它,修改后的代码如下...我们从汇编指令开始,一起讨论了寄存器,内存,栈,函数调用过程,操作系统内核对线程的调度以及线程本地存储等内容,相信读者已经很好的掌握了这些基础知识,接下来就让我们一起来撩开goroutine调度器的神秘面纱吧
操作系统把磁盘上的可执行文件加载到内存运行之前,会做很多工作,其中很重要的一件事情就是把可执行文件中的代码,数据放在内存中合适的位置,并分配和初始化程序运行过程中所必须的堆栈,所有准备工作完成后操作系统才会调度程序起来运行...AMD64 CPU提供了2个与栈相关的寄存器: rsp寄存器,始终指向函数调用栈栈顶 rbp寄存器,一般用来指向函数栈帧的起始位置 下面用两个图例来说明一下函数调用栈以及rsp/rbp与栈之间的关系。...; 有些编译器比如gcc会把参数和返回值放在寄存器中而不是栈中,go语言中函数的参数和返回值都是放在栈上的; 随着程序的运行,如果C、B两个函数都执行完成并返回到了A函数继续执行,则栈状态如下图: ?...,当它发现程序返回了某个局部变量的地址,编译器会把这个变量放到堆上去,而不会放在栈上。...同样,这里我们还是需要注意rbp和rsp这两个寄存器现在指向了D函数的栈帧。从上面的分析我们可以看出,寄存器rbp和rsp始终指向正在执行的函数的栈帧。
文章目录 一、调度子系统组件模块 二、主调度器、周期性调度器 三、调度器类 一、调度子系统组件模块 ---- 调度器 需要对 被调度的进程 进行 排序 和 调度管理 , 进程管理过程需要 调度器 的 组件模块..., 以及相关 算法 数据结构 来完成 , 如 : 执行队列 ; 二、主调度器、周期性调度器 ---- CPU 通过 " 上下文切换 " 选择 " 主调度器 " 或 " 周期性调度器 " , " 上下文切换..." 主要完成 切换地址空间 , 切换寄存器 , 切换栈空间 工作 ; " 主调度器 " 通过 调用 schedule() 方法 , 完成 进程的 调度 和 切换 ; " 周期性调度器 " 根据 相应频率..., 自动调用 scheduler_tick() 函数 , 完成调度 , 这是根据 进程 运行时间 , 自动触发进程调度 ; 三、调度器类 ---- 主调度器 或 周期性调度器 根据 不同的 " 选择进程..." 选择不同的 调度器类 , 可选的调度类参考 【Linux 内核】调度器 ⑦ ( 调度器类型 | 停机调度类 stop_sched_class | 限期调度类 dl_sched_class | 实时调度类
go语言runtime(包括调度器)源代码中有部分代码是用汇编语言编写的,不过这些汇编代码并非针对特定体系结构的汇编代码,而是go语言引入的一种伪汇编,它同样也需要经过汇编器转换成机器指令才能被CPU执行...除了这些跟AMD64 CPU硬件寄存器一一对应的寄存器外,go汇编还引入了几个没有任何硬件寄存器与之对应的虚拟寄存器,这些寄存器一般用来存放内存地址,引入它们的主要目的是为了方便程序员和编译器用来定位内存中的代码和数据...first_arg+0(FP) 来引用调用者传递进来的第一个参数,用second_arg+8(FP)来引用第二个参数 ,以此类推,这里的first_arg和second_arg仅仅是一个帮助我们阅读源代码的符号...,对编译器来说无实际意义,+0和+8表示相对于FP寄存器的偏移量。...go汇编还有一些用法比较特别的地方,现在不讨论,等我们分析源代码遇到它们时再结合上下文做详细说明。
class PageHelper { /** * 对一个列表进行分页 * @param list 列表 * @param...
O(n) 调度器。...O(1) 调度器 在 linux 内核采用 O(n) 调度器的 4 年后,Linux2.6.0 采纳了 Rad Hat 公司设计的 O(1) 调度算法,这是一个基于上一篇文章中介绍的多级反馈队列算法的调度器实现...4.1 调度器分层思想 而事实证明,在公平策略调度器基础上改进设计的 CFS 确实是一款优秀的调度器,它的思想是将调度器进行模块化,从而让操作系统中可以有多种调度器以不同的策略和优先级来执行。...操作系统中,调度器由此分为四层: DL 调度器:采用 sched_deadline 策略; RT 调度器:采用 sched_rr 和 sched_fifo 策略; CFS 调度器:采用 sched_normal...O(n) 调度器这类通过分配固定时间片的调度器所不能实现的。
解决了这些问题,我们对计算机执行程序的原理就有了一个大致的了解,这对于我们理解goroutine的调度有非常重要的作用。...为了更加清晰的理解程序的执行流程,现在我们开始模拟CPU从main函数的第一条指令开始,一直到执行完整个main函数。...main函数需要使用这个寄存器来存放自己的栈基地址,而调用者在调用main函数之前也把它的栈基地址保存在了这个寄存器里面,所以main函数需要把这个寄存器里面的值先保存起来,等main执行完后返回时再把这个寄存器恢复原样...该指令执行完成之后,从rsp所指位置到rbp所指的这一段栈内存就构成了main函数的完整栈帧,其大小为40字节(8字节用于保存调用者的rbp,另外32字节用于main函数的局部和临时变量),如下图: ?...第一条add指令负责执行加法运算并把结果3存入eax寄存器,第二条指令负责把eax寄存器的值保存到了s变量所在的内存,第三条指令又把s变量的值读取到eax寄存器,可以看到局部变量s被编译器安排在了rbp
文章目录 一、调度器 0、调度器概念 1、调度器目的 2、调度器主要工作 3、调度器位置 4、进程优先级 5、抢占式调度器 二、Linux 内核进程状态 API 简介 三、Linux 进程状态 一、调度器...---- 0、调度器概念 Linux 内核的 " 进程调度 " 是按照 设计好的调度算法 安排的 , 该算法对应的功能模块 称为 " 调度器 " , 英文名称是 Scheduler ; 1、调度器目的...进程调度 目的是 最大限度利用 CPU 资源 , 也就是 CPU 时间片 ; 2、调度器主要工作 " 调度器 " 主要的工作 : ① 就绪 -> 执行 : 选择 " 就绪状态 " 的进程执行 ; (..." , 主要是 " 就绪状态 " 与 " 执行状态 " 这两个状态之间相互切换 ; 3、调度器位置 调度器 在 如下的 进程状态图 中的位置是 " 就绪状态 " 与 " 运行状态 " 之间 ; 就绪状态..." 抢占式调度器 " 概念 : 如果 " 调度器 " 支持 " 就绪状态 " 与 " 运行状态 " 之间可以相互转换 , 则该调度器称为 " 抢占式调度器 " ; 二、Linux 内核进程状态 API
上一篇文章《Go语言高阶:调度器系列(1)起源》,学goroutine调度器之前的一些背景知识,这篇文章则是为了对调度器有个宏观的认识,从宏观的3个角度,去看待和理解调度器是什么样子的,但仍然不涉及具体的调度原理...Scheduler的宏观组成 Tony Bai在《也谈goroutine调度器》中的这幅图,展示了goroutine调度器和系统调度器的关系,而不是把二者割裂开来,并且从宏观的角度展示了调度器的重要组成...Goroutine调度器和OS调度器是通过M结合起来的,每个M都代表了1个内核线程,OS调度器负责把内核线程分配到CPU的核上执行。...调度器的生命周期 接下来我们从另外一个宏观角度——生命周期,认识调度器。 所有的Go程序运行都会经过一个完整的调度器生命周期:从创建到结束。 ?...总结时刻 这篇文章,从3个宏观的角度介绍了调度器,也许你依然不知道调度器的原理,心里感觉模模糊糊,没关系,一步一步走,通过这篇文章希望你了解了: Go调度器和OS调度器的关系 Go调度器的生命周期/总体流程
应用场景,一般一个单位的资源有限,需要怎样调度资源是非常考验人的事情。...还有会议室也是这样,一个会议室还好办,4个会议室,就没法调度了…… 这个小程序就是一个日历,点击日期,添加公告……可以添加当天,或者今天以后的,今天之前的,就不允许修改了。
本文链接:https://blog.csdn.net/xxzhangx/article/details/103386769 总结工作中使用到的调度方案 包括的内容如下: 1、定时调度 使用python...脚本、airflow 调度平台 脚本参数设置 subprocess、command等执行shell nohup后台执行 airflow 2、异常邮件告警 异常邮件告知 发送邮件 3、hadoop
这就涉及goroutine的G-P-M调度模型。 G-P-M调度模型 Golang能够拥有强大的并发能力需要归功于G-P-M调度模型,首先需要解释G、P、M分别代表什么: ?...P 代表Processor,逻辑处理器。P维护Goroutine各种队列,mcache和状态。P的数量决定了最大可并行的Goroutine数量(前提:系统物理CPU核数>=P数量)。...调度逻辑 ? 从图中可以看出,一共有两个物理线程M,每个M都绑定一个处理器P,每个P维护一个就绪状态的Goroutine队列,灰色的表示在等待P调度,蓝色的G代表正绑定P在M中执行。...当执行的Goroutine(G0)调度阻塞的系统调度时,P会切到另外的M'中,如果没有可用的M'就会创建一个,继续执行队列中的G。...总结 文章介绍了Golang自带的goroutine调度器G-P-M调度模型,G-P-M调度算法最大限度的发挥了并发性能,同时在一些异常情况下也能正常快速调度。
SMP调度 多处理器系统上,内核必须考虑几个额外的问题,以确保良好的调度。 CPU负荷必须尽可能公平地在所有的处理器上共享。...特定于调度器类的函数接下来建立一个迭代器,使得核心调度器能够遍历所有可能迁移到另一个队列的备选进程,但各个调度器类的内部结构不能因为迭代器而暴露给核心调度器。...1.3 核心调度器的改变 除了上述增加的特性之外,在SMP系统上还需要对核心调度器的现存方法作一些修改。虽然到处都是一些小的细节变化,与单处理器系统相比最重要的差别如下所示。...完全公平调度器的调度粒度与CPU的数目是成比例的。系统中处理器越多,可以采用的调度粒度就越大。...调度域和控制组 在此前对调度器代码的讨论中,调度器并不直接与进程交互,而是处理可调度实体。这使得可以实现组调度:进程置于不同的组中,调度器首先在这些组之间保证公平,然后在组中的所有进程之间保证公平。
领取专属 10元无门槛券
手把手带您无忧上云