操作系统学习(三):浅析比例份额调度——彩票调度和步长调度

简介: 比例份额(proportional-share)算法基于一个简单的想法:调度程序的最终目标,是确保每个工作获得一定比例的 CPU 时间,而不是优化周转时间和响应时间。

1、简单介绍


     

比例份额(proportional-share)算法基于一个简单的想法:调度程序的最终目标,是确保每个工作获得一定比例的 CPU 时间,而不是优化周转时间和响应时间。


他有一种简单的实习——彩票调度(lottery scheduling),十分简单:每隔一段时间,都会举行一次彩票抽奖,以确定接下来应该运行哪个进程。越是应该频繁运行的进程,越是应该拥有更多地赢得彩票的机会。


接下来就涉及细节问题了?如何设计调度程序来按比例分配 CPU?其关键的机制是什么?效率如何?


2、基本概念



彩票调度背后是一个非常基本的概念:彩票数(ticket)代表了进程(或用户或其他)占有某个资源的份额。一个进程拥有的彩票数占总彩票数的百分比,就是它占有资源的份额。


下面来看一个例子。假设有两个进程 A 和 B,A 拥有 75 张彩票,B 拥有 25 张。因此我们希望 A 占用 75%的 CPU 时间,而 B 占用 25%。


通过不断定时地(比如,每个时间片)抽取彩票,彩票调度从概率上(但不是确定的)获得这种份额比例。抽取彩票的过程很简单:调度程序知道总共的彩票数(在我们的例子中,有 100 张)。调度程序抽取中奖彩票,这是从 0 和 99①之间的一个数,拥有这个数对应的彩票的进程中奖。假设进程 A 拥有 0 到 74 共 75 张彩票,进程 B 拥有 75 到 99 的 25 张,中奖的彩票就决定了运行 A 或 B。调度程序然后加载中奖进程的状态,并运行它。


可以看出,彩票调度中利用了随机性,这导致了从概率上满足期望的比例,但并不能确保。但是,工作运行得时间越长,它们得到的 CPU 时间比例就会越接近期望。


3、优点



彩票调度最精彩的地方在于利用了随机性(randomness)。当你需要做出决定时,采用随机的方式常常是既可靠又简单的选择。


随机方法相对于传统的决策方式,至少有 3 点优势:


第一,随机方法常常可以避免奇怪的边角情况,较传统的算法可能在处理这些情况时遇到麻烦。例如 LRU 替换策略。虽然 LRU 通常是很好的替换算法,但在有重复序列的负载时表现非常差。但随机方法就没有这种最差情况。


第二,随机方法很轻量,几乎不需要记录任何状态。在传统的公平份额调度算法中,记录每个进程已经获得了多少的 CPU 时间,需要对每个进程计时,这必须在每次运行结束后更新。而采用随机方式后每个进程只需要非常少的状态(即每个进程拥有的彩票号码)。


第三,随机方法很快。只要能很快地产生随机数,做出决策就很快。因此,随机方式在对运行速度要求高的场景非常适用。当然,越是需要快的计算速度,随机就会越倾向于伪随机。


4、彩票机制



彩票调度还提供了一些机制,以不同且有效的方式来调度彩票。


4.1 彩票货币(ticket currency)

     

类似于加权。这种方式允许拥有一组彩票的用户以他们喜欢的某种货币,将彩票分给自己的不同工作。之后操作系统再自动将这种货币兑换为正确的全局彩票。

     

比如,假设用户 A 和用户 B 每人拥有 100 张彩票。用户 A 有两个工作 A1 和 A2,他以自己的货币,给每个工作 500 张彩票(共 1000 张)。用户 B 只运行一个工作,给它 10 张彩票(总共 10 张)。操作系统将进行兑换,将 A1 和 A2 拥有的 A 的货币 500 张,兑换成全局货币 50 张。类似地,兑换给 B1 的 10 张彩票兑换成 100 张。然后会对全局彩票货币(共 200张)举行抽奖,决定哪个工作运行。


4.2 彩票转让(ticket transfer)

     

通过转让,一个进程可以临时将自己的彩票交给另一个进程。这种机制在客户端/服务端交互的场景中尤其有用,在这种场景中,客户端进程向服务端发送消息,请求其按自己的需求执行工作,为了加速服务端的执行,客户端可以将自己的彩票转让给服务端,从而尽可能加速服务端执行自己请求的速度。服务端执行结束后会将这部分彩票归还给客户端。


4.3 彩票通胀(ticket inflation)

     

通胀可以用于进程之间相互信任的环境。在这种情况下,如果一个进程知道它需要更多 CPU 时间,就可以增加自己的彩票,从而将自己的需求告知操作系统,这一切不需要与任何其他进程通信。


5、实现


     

彩票调度中最不可思议的,或许就是实现简单。只需要一个不错的随机数生成器来选择中奖彩票和一个记录系统中所有进程的数据结构(一个列表),以及所有彩票的总数。


// 计数器
int counter = 0;
// 随机数生成0到总数之间的值
int winner = getrandom(0, totaltickets); 
// 用来遍历工作列表的当前指针
node_t *current = head; 
while (current) { 
    counter = counter + current->tickets; 
    if (counter > winner) 
        break;
    current = current->next; 
}


6、缺点


     

从上面的内容可以看出,虽然随机方式可以使得调度程序的实现简单(且大致正确),但偶尔并不能产生正确的比例,尤其在工作运行时间很短的情况下。


因此,我们还需要介绍一种确定性的公平分配算法——步长调度(stride scheduling)


7、步长调度(stride scheduling)



步长调度也很简单。系统中的每个工作都有自己的步长,这个值与票数值成反比。在上面的例子中,A、B、C 这 3 个工作的票数分别是 100、50 和 250,我们通过用一个大数分别除以他们的票数来获得每个进程的步长。比如用 10000 除以这些票数值,得到了 3 个进程的步长分别为 100、200 和 40。我们称这个值为每个进程的步长(stride)。每次进程运行后,我们会让它的计数器 [称为行程(pass)值] 增加它的步长,记录它的总体进展。


之后,调度程序使用进程的步长及行程值来确定调度哪个进程。基本思路很简单:当需要进行调度时,选择目前拥有最小行程值的进程,并且在运行之后将该进程的行程值增加一个步长。


在我们的例子中,3 个进程(A、B、C)的步长值分别为 100、200 和 40,初始行程值都为 0。因此,最初,所有进程都可能被选择执行。假设选择 A(任意的,所有具有同样低的行程值的进程,都可能被选中)。A 执行一个时间片后,更新它的行程值为 100。然后运行 B,并更新其行程值为 200。最后执行 C,C 的行程值变为 40。这时,算法选择最小的行程值,是 C,执行并增加为 80(C 的步长是 40)。然后 C 再次运行(依然行程值最小),行程值增加到 120。现在运行 A,更新它的行程值为 200(现在与 B 相同)。然后 C 再次连续运行两次,行程值也变为 200。此时,所有行程值再次相等,这个过程会无限地重复下去。


current = remove_min(queue);         // pick client with minimum pass 
schedule(current);                   // use resource for quantum 
current->pass += current->stride;    // compute next pass using stride 
insert(queue, current);              // put back into the queue

     

既然有了可以精确控制的步长调度算法,为什么还要彩票调度算法呢?好吧,彩票调度有一个步长调度没有的优势——不需要全局状态。假如一个新的进程在上面的步长调度执行过程中加入系统,应该怎么设置它的行程值呢?设置成 0 吗?这样的话,它就独占 CPU 了。而彩票调度算法不需要对每个进程记录全局状态,只需要用新进程的票数更新全局的总票数就可以了。因此彩票调度算法能够更合理地处理新加入的进程。


相关文章
|
22天前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
2天前
|
消息中间件 算法 调度
深入理解操作系统:进程管理与调度策略
【10月更文挑战第29天】本文将带领读者深入探讨操作系统中的核心组件之一——进程,并分析进程管理的重要性。我们将从进程的生命周期入手,逐步揭示进程状态转换、进程调度算法以及优先级调度等关键概念。通过理论讲解与代码演示相结合的方式,本文旨在为读者提供对进程调度机制的全面理解,从而帮助读者更好地掌握操作系统的精髓。
|
2天前
|
算法 调度 UED
深入理解操作系统中的进程调度
【10月更文挑战第29天】探索进程调度的奥秘,本文将带你深入了解在操作系统中如何管理和控制多个并发执行的程序。从简单的调度算法到复杂的多级反馈队列,我们将逐步揭示如何优化系统性能和提高资源利用率。准备好一起揭开进程调度的神秘面纱吧!
|
7天前
|
算法 大数据 Linux
深入理解操作系统之进程调度算法
【10月更文挑战第24天】本文旨在通过浅显易懂的语言,带领读者深入了解操作系统中的进程调度算法。我们将从进程的基本概念出发,逐步解析进程调度的目的、重要性以及常见的几种调度算法。文章将通过比喻和实例,使复杂的技术内容变得生动有趣,帮助读者建立对操作系统进程调度机制的清晰认识。最后,我们还将探讨这些调度算法在现代操作系统中的应用和发展趋势。
|
20天前
|
分布式计算 算法 大数据
探索操作系统的核心:调度与内存管理机制
【10月更文挑战第11天】 本文深入探讨了操作系统中两大核心功能——调度与内存管理机制。通过分析调度算法、进程状态转换及内存分配策略等关键方面,揭示了它们如何共同维护系统性能和稳定性。旨在为读者提供对操作系统内部运作的深刻理解,同时引起对优化策略的思考。
45 5
|
24天前
|
算法 调度 UED
探索操作系统的心脏:深入理解进程调度
【10月更文挑战第7天】在数字世界的海洋中,操作系统是那艘承载着软件与硬件和谐共处的巨轮。本文将带你潜入这艘巨轮的核心区域——进程调度系统,揭示它如何精准控制任务的执行顺序,保障系统的高效运行。通过深入浅出的语言,我们将一起解码进程调度的奥秘,并借助代码示例,直观感受这一机制的魅力所在。准备好,让我们启航吧!
|
24天前
|
算法 调度 UED
深入理解操作系统的进程调度算法
【10月更文挑战第7天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。它不仅影响系统的性能和用户体验,还直接关系到资源的合理分配。本文将通过浅显易懂的语言和生动的比喻,带你一探进程调度的秘密花园,从最简单的先来先服务到复杂的多级反馈队列,我们将一起见证算法如何在微观世界里编织宏观世界的和谐乐章。
|
2天前
|
算法 调度 开发者
探索操作系统的核心:进程管理与调度
【10月更文挑战第29天】本文深入探讨了操作系统中至关重要的一环——进程管理。通过浅显易懂的语言,我们将了解到什么是进程,进程如何被创建和管理,以及操作系统如何决定哪个进程应该获得CPU时间。文章还将揭示进程调度对系统性能的影响,并分享一些优化技巧。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识。
|
22天前
|
算法 Unix Linux
深入理解操作系统:进程管理与调度策略
【10月更文挑战第9天】本文将带你进入操作系统的核心,探索进程管理的奥秘。我们将从基础的概念出发,逐步深入到进程的创建、调度和同步等关键机制。通过理论与实际代码示例的结合,你将获得对操作系统中进程管理更深层次的理解和应用能力。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和知识,让你在操作系统的学习之旅上更进一步。
|
26天前
|
算法 调度 开发者
操作系统的心脏:深入理解进程调度
本文将探讨操作系统中至关重要的部分——进程调度。进程调度负责管理计算机的CPU时间分配,确保多任务环境中每个进程都能公平地获得处理资源。通过深入分析不同的调度算法,如先来先服务(FCFS)、短作业优先(SJF)和优先级调度,本文揭示了它们的优势、缺陷及适用场景。我们还将讨论现代操作系统如何实现这些算法,并评估多级反馈队列等高级调度策略如何提高系统效率。无论是开发者设计更高效的应用程序,还是用户优化自己的使用体验,了解进程调度的基本原理和实践应用都是不可或缺的一环。