企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 调度,第 1 部分:调度过程 > 原文:<https://github.com/angrave/SystemProgramming/wiki/Scheduling%2C-Part-1%3A-Scheduling-Processes> ## 关于调度的思考。 [CPU 调度](https://en.wikipedia.org/wiki/Scheduling_(computing))是有效选择在系统 CPU 内核上运行哪个进程的问题。在繁忙的系统中,将有比 CPU 内核更多的可立即运行的进程,因此系统内核必须评估应该在 CPU 上运行哪些进程以及哪些进程应放在就绪队列中以便稍后执行。 多线程和多 CPU 内核的额外复杂性被认为是对这个初始展示的干扰,因此在此忽略。 非母语人士的另一个问题是“时间”的双重含义:“时间”一词可用于时钟和经过时间的上下文。例如“第一个过程的到达时间是上午 9 点。”并且,“算法的运行时间是 3 秒”。 ## 如何测量调度以及哪种调度程序最佳? 调度会影响系统的性能,特别是系统的 _ 延迟 _ 和 _ 吞吐量 _。吞吐量可以通过系统值来度量,例如 I / O 吞吐量 - 每秒写入的字节数,或者每单位时间可以完成的小进程数,或者使用更高级别的抽象,例如客户数量每分钟处理的记录。延迟可以通过响应时间(进程可以开始发送响应之前的经过时间)或等待时间或周转时间(完成任务所经过的时间)来度量。不同的调度程序提供不同的优化权衡,可能适合或不适合所需的使用 - 没有针对所有可能的环境和目标的最佳调度程序。例如,“shortest-job-first”将最小化所有作业的总等待时间,但在交互式(UI)环境中,最好将响应时间最小化(以某些吞吐量为代价),而 FCFS 看起来直观公平且易于实现但是遭遇了康宏效应。 ## 什么是到达时间? 进程首次到达就绪队列并准备开始执行的时间。如果 CPU 空闲,则到达时间也将是执行的开始时间。 ## 什么是先发制人? 在没有抢占的情况下,进程将一直运行,直到它们无法再进一步利用 CPU。例如,以下条件将从 CPU 中删除进程,并且可以为其他进程调度 CPU:进程由于信号而终止,被阻塞等待并发原语或正常退出。因此,一旦调度了一个进程,即使具有高优先级的另一个进程(例如,较短的作业)出现在就绪队列上,它也将继续。 通过抢占,如果将更优选的进程添加到就绪队列,则可以立即移除现有进程。例如,假设在 t = 0 时使用 Shortest Job First 调度程序,有两个进程(P1 P2),执行时间为 10 和 20 ms。 P1 已预定。 P1 立即创建一个新进程 P3,执行时间为 5 毫秒,并将其添加到就绪队列中。没有先发制人,P3 将在 10ms 后运行(P1 完成后)。通过抢占,P1 将立即从 CPU 中逐出,而是放回到就绪队列中,而 P3 将由 CPU 执行。 ## 哪些调度员遭受饥饿? 任何使用优先级形式的调度程序都可能导致饥饿,因为可能永远不会调度早期进程(分配 CPU)。例如,对于 SJF,如果系统继续有许多要安排的短作业,则可能永远不会安排更长的作业。这一切都取决于[类型的调度程序](https://en.wikipedia.org/wiki/Scheduling_(computing)#Types_of_operating_system_schedulers)。 ## 为什么可以将一个进程(或线程)放在就绪队列上? 当一个进程能够使用 CPU 时,该进程被置于就绪队列中。一些例子包括: * 阻止进程等待存储或套接字中的`read`完成,现在可以使用数据。 * 已创建新进程并准备启动。 * 进程线程在同步原语(条件变量,信号量,互斥锁)上被阻止,但现在能够继续。 * 阻止进程等待系统调用完成,但已传递信号并且信号处理程序需要运行。 在考虑线程时可以生成类似的示例。 ## 效率措施 `start_time`是进程的挂钟开始时间(CPU 开始工作)`end_time`是进程的结束挂钟(CPU 完成进程)`run_time`是所需的 CPU 时间总量`arrival_time`是进程进入调度程序的时间(CPU 可能无法启动它) ## 什么是'周转时间'? 从进程到达到结束的总时间。 `turnaround_time = end_time - arrival_time` ## 什么是'响应时间'? 从进程到达到 CPU 实际开始工作所花费的总延迟(时间)。 `response_time = start_time - arrival_time` ## 什么是“等待时间”? 等待时间是 _ 总 _ 等待时间,即进程在就绪队列上的总时间。一个常见的错误是认为它只是就绪队列中的初始等待时间。 如果没有 I / O 的 CPU 密集型进程需要 7 分钟的 CPU 时间才能完成,但需要 9 分钟的挂钟时间才能完成,我们可以得出结论,它已被放置在就绪队列中 2 分钟。对于那些 2 分钟,该过程已准备好运行但没有分配 CPU。工作等待时无关紧要,等待时间为 2 分钟。 `wait_time = (end_time - arrival_time) - run_time` ## 什么是车队效应? “Convoy 效应是持续备份 I / O 密集型进程的地方,等待占用 CPU 的 CPU 密集型进程。这导致 I / O 性能不佳,即使对于 CPU 需求很小的进程也是如此。” 假设 CPU 当前已分配给 CPU 密集型任务,并且存在一组处于就绪队列中的 I / O 密集型进程。这些进程只需要很少的 CPU 时间,但它们无法继续,因为它们正在等待从处理器中删除 CPU 密集型任务。在 CPU 绑定进程释放 CPU 之前,这些进程一直处于饥饿状态。但很少会释放 CPU(例如,在 FCFS 调度程序的情况下,我们必须等到进程因 I / O 请求而被阻止)。 I / O 密集型进程现在可以最终满足他们的 CPU 需求,他们可以快速完成这些需求,因为他们的 CPU 需求很小,并且 CPU 再次被分配回 CPU 密集型进程。因此,整个系统的 I / O 性能受到所有进程的 CPU 需求饥饿的间接影响。 这种效果通常在 FCFS 调度程序的上下文中讨论,但循环调度程序也可以展示长时间量子的康宏效应。 ## Linux 调度 截至 2016 年 2 月,Linux 默认使用 _ 完全公平调度程序 _ 进行 CPU 调度,使用预算公平调度“BFQ”进行 I / O 调度。适当的调度会对吞吐量和延迟产生重大影响。延迟对于交互式和软实时应用(如音频和视频流)尤为重要。有关详细信息,请参阅此处的讨论和比较基准[ [https://lkml.org/lkml/2014/5/27/314](https://lkml.org/lkml/2014/5/27/314) ]。 以下是 CFS 的日程安排 * CPU 创建一个红黑树,其中包含进程虚拟运行时(runtime / nice_value)和睡眠公平性(如果进程正在等待某些内容,则在等待时将其提供给 CPU)。 * (好的值是内核优先处理某些进程的方式,优先级越低) * 内核根据此度量标准选择最低的一个,并安排该进程下一次运行,将其从队列中取出。由于红黑树是自平衡的,因此保证$ O(log(n))$(选择 min 进程是相同的运行时) 虽然它被称为公平调度程序,但存在一些问题。 * 调度的进程组可能具有不平衡负载,因此调度程序粗略地分配负载。当另一个 CPU 获得空闲时,它只能查看组计划的平均负载而不是单个核心。因此,只要平均值很好,空闲 CPU 就不会从正在燃烧的 CPU 中获取工作。 * 如果一组进程正在运行,则在非相邻核心上存在错误。如果两个核心超过一跳,负载平衡算法甚至不会考虑该核心。这意味着如果 CPU 是空闲的并且正在做更多工作的 CPU 超过一跳,它将不会进行工作(可能已经修补)。 * 线程在一个核心子集上进入休眠状态后,当它被唤醒时,它只能在它正在睡眠的核心上进行调度。如果这些核心现在是公共汽车