操作系统导论(2)

进程的调度

  • 考虑因素

    1. 为了构建调度策略,需要做一些简化假设,这些假设和系统中运行的进程相关,统称为工作负载(workload)

      (1)每一个进程(工作)运行相同的时间

      (2)所有工作同时到达,有时候当多个工作到达的时间相差很小的时候,也近似认为是同时到达的

      (3)一旦开始工作,每个工作将保持运行直到完成

      (4)所有工作只是使用CPU,即:它们不执行I/O操作

      (5)每个工作的运行时间已知

    2. 为了能够衡量不同调度策略的优缺点,提出一个指标——周转时间(turnaround time)

      (1)定义:任务完成时间减去任务到达的时间,即:

在这里插入图片描述

 (2)当满足假设同时到达时,到达时间为0,周转时间等于完成时间

 (3)周转时间是一个**性能**(performance)**指标**。而性能和公平在调度系统往往时矛盾的。调度系统可以优化性能,但代价时阻止一些任务运行,这就降低了公平
  • 先进先出(FIFO)

    1. 先进先出(First In First Out):先就绪的工作先执行
    2. 假设有A、B、C三个工作,A比B早一点点,B比C早一点点,此时根据我们的假设,可以将A、B、C近似看作时同时到达的。但是根据实际情况,是A先执行,其次是B,最后是C。假设每个工作运行10s,求工作的平均周转时间(average turnaround time)?
      操作系统导论(2)_第1张图片
 A的周转时间为10s,B的周转时间为20s,C的周转时间为30s

 平均周转时间为(10+20+30)/3=20
    1. 现在放宽假设1,让A、B、C运行时间不同,考虑FIFO是否存在平均周转时间较长的情况
    2. 假设A、B、C三个工作,A运行时间为100s,B和C运行时间为10s,如果依旧是A先早到一点,然后是B,最后是C(仍然近似认为是同时到达的),此时系统的平均周转时间较长(100+110+120)/3=110

      操作系统导论(2)_第2张图片

    3. FIFO出现4这种情况被称为护航效应(convoy effect),即:一些耗时较少的潜在资源消耗者排在重量级的资源消费者后面。例如:在杂货店只有一个排队队伍的时候,你看见前面的装满了3辆购物车的货物时,这会让你等很长时间
    • 最短任务优先(SJF)

      1. 最短任务优先(Shortest Job First):先运行最短的时间,然后是次短的时间,如此继续
      2. 依旧在上述4的情况下,按照SJF的策略,平均周转时间为(10+20+120)/3=50,和FIFO相比,显著降低了平均周转时间。但前提是满足假设2——同时到达
        操作系统导论(2)_第3张图片
      3. 现在放宽假设2,即:工作能够随时到达,考虑SJF平均周转时间较长的情况
      4. 依旧是FIFO中4的情况,假设A在t=0时到达,并且需要运行100s,而B和C在t=10s到达,各自运行10s。则A的周转时间为100s,B的周转时间为110-10=100,C的周转时间为120-10=110。平均周转时间为(100+100+110)/3=103.33s
      5. 很明显当工作能够随时到达的情况下,SJF可能会出现平均周转时间较长的情况
    • 最短完成时间优先(STCF)

      1. 最短完成时间优先(Shortest Time-to-Completion First):放宽假设3,即:调度程序可以安排其它工作抢占正在运行的工作占用的CPU。
      2. 在SJF中添加了抢占,每当新工作进入就绪状态时,它就会确定剩余工作和新工作中,谁的完成时间最少,然后调度这个工作
      3. 在上述4的情况下,STCF将抢占A并先运行完B和C后,才会继续运行。则A的周转时间为120s,B的周转时间为10s,C的周转时间为20s,平均周转时间为(120+10+20)/3=50,显著降低了SJF相同情况下的平均周转时间

        操作系统导论(2)_第4张图片

    • 增加考虑因素

      1. 当符合假设4、5成立时,即:知道任务长度,并且任务只使用CPU,根据当前的唯一衡量指标为周转时间时,STCF是一个很好的策略。但是,引入分时系统时,就出现了问题,因为此时需要任务和用户进行交互,而周转时间无法衡量任务的交互性
      2. 响应时间(response time):能够衡量任务的交互性,定义为从任务到达系统到首次运行的时间
        在这里插入图片描述
    • 轮转(RR)

      1. 轮转(Round-Robin):在一个时间片内运行一个工作,然后切换到运行队列的下一个任务,而不是运行一个任务直到结束。它反复执行,直到所有任务完成。
      2. 时间片长度必须时时钟周期的倍数。如果不是,进行上下文切换的时候需要等待一段时间,此时CPU没工作,就浪费了CPU资源
      3. 假设3个任务,A、B、C在系统中同时到达,并且它们都希望运行5s,SJF调度程序必须运行完当前任务才能运行下一个任务,而1s时间片的RR能够快速循环工作。RR平均响应时间为:(0+1+2)/3=1(注:同时到达,到达时间为0),SJF算法平均响应时间为(0+5+10)/3=5

    操作系统导论(2)_第5张图片

    1. 时间片长度对RR至关重要,越短,RR在响应时间上的表现越好,但是时间片不能设置得太短:突然上下文切换会影响整体性能。因为上下文切换的成本不仅仅来自保存和恢复少量寄存器的操作系统操作。程序在运行时,还会在CPU高速缓存、TLB、分支预测器和其他片上的硬件中建立了大量的状态。所以时间片长度需要慎重权衡,让它足够长,以便摊销上下文切换成本,而又不会让系统不及时响应
    2. 摊销(amortize):通过减少成本的频度(即:执行较少的操作),系统的总成本就会降低。例如:如果时间片设置为10ms,并且上下文切换时间为1ms,大约会浪费10%的时间用于上下文切换。为了摊销这个成本,可以把时间片长度增加到100ms,则只有不到1%的时间会用于上下文切换。
    3. 在3中,我们只考虑了响应时间,没考虑周转时间,如果计算RR的周转时间,A为13,B为14,C为15,平均14。而SJF的周转时间为,A为5,B为10,C为15,平均10.此时RR虽然响应时间较好,但是周转时间较差。
    4. 到目前为止。有两类调度程序

      (1)SJF、STCF优化了周转时间,但是响应时间——交互性不好

      (2)RR优化了响应时间,但是周转时间不好

    • 结合I/O

      1. 放宽假设4,即:工作会执行I/O,此时调度程序会面临两个问题

        (1)发起I/O请求做出决定,因为当前运行的任务在I/O期间不会使用CPU,它会被阻塞等待I/O完成。这时调度程序需要考虑是否等待该任务的执行还是安排另一项任务

        (2)I/O完成时做出决定。I/O完成时会产生中断,操作系统运行并将发出I/O的进程从阻塞状态移回到就绪状态。此时调度程序将考虑是继续执行该任务,还是执行其他任务

      2. 假设有两项工作A、B,每项工作需要50ms的CPU时间。A每运行10ms,就会发出一次I/O请求,而B只是单纯地使用CPU50ms.调度程序先运行A再运行B。假设构建STCF调度程序。可以将A的每个10ms的子工作看作是一项独立的工作。所以任务运行时,先执行A10ms的子任务,完成后,会执行B,当I/O请求完成后,就会抢占B并运行10ms,这样就会充分利用系统。

        操作系统导论(2)_第6张图片

      3. 当交互式作业(即:I/O请求较多)正在执行I/O时,其他CPU密集型任务(即:I/O操作很少)将运行,从而更好的利用处理器
    • 多级反馈队列(MLFQ)

      1. 多级反馈队列(Multi-level Feedback Queue,MLFQ)需要解决的问题

        (1)优化周转时间

        (2)放宽假设5,即:不知道任务运行时间

        (3)降低响应时间,获取更好的交互体验

      2. 基本构成:有许多独立的队列,每个队列有不同的优先级(priority level)
      3. 基本规则:

        (1)规则1:如果A的优先级>B的优先级,运行A(不运行B)

        (2)规则2:如果A的优先级=B的优先级,轮转运行A和B

      4. 如何改变优先级(1)?

        (1)系统需要执行的任务可以分为下列两类

        ​ a. 运行时间很短、频繁放弃CPU的交互性任务

        ​ b. 需要很多CPU时间、响应时间不是很重要的长时间计算密集型任务

        (2)优先级调整算法

        ​ a. 规则3:任务进入系统时,放在最高优先级(最上层队列)

        ​ b. 规则4a:任务用完整个时间片后,降低优先级(移入下一个队列)

        ​ c. 规则4b:如果工作再其时间片内主动释放CPU,则优先级不变

        (3)实例1:单个长工作

        下图展示了一个有三个队列的调度程序。该工作首先进入最高优先级(Q2),执行10ms的时间片后,优先级-1,最终进入Q1,并一直到执行完毕

        操作系统导论(2)_第7张图片

     (4)实例2:来了一个短工作
    
     有两个工作:A时一个长时间运行的CPU密集任务,B是一个运行时间很短的交互型任务。假设A执行一段时间后B到达。下图中A(用黑色表示)在最低优先队列中(由(3)可知:长时间任务很长时间都会在最低队列中),B(用灰色表示)在时间T=100时到达,并加入最高优先级队列中。由于它运行时间很短,经过两个时间片,在被移入最低优先级队列之前,B执行完毕。然后A继续运行。
    
     ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200927185023424.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzI2NzQ0,size_16,color_FFFFFF,t_70#pic_center)
    
    
     (5)MLFQ算法的目标:如果不知道任务时短任务还是长任务,那么就在考试的时候假设它时短任务,并赋予最高优先级。如果确实是短任务,则会很快执行完毕。否则就会被慢慢移入低优先级队列,而这个时候该任务也被认为是长任务了。通过这种方式,MLFQ近似于SJF。
    
     (6)实例3:有I/O
    
     根据4b,交互型工作中有大量的I/O操作(比如等待用户的键盘或鼠标输入),它会在时间片用完之前放弃CPU,在这种情况下,我们会保持它的优先级不变
    
     假设交互型工作B(用灰色表示)每执行1ms便需要进行I/O操作,它与长时间运行的工作A(用黑色表示)竞争CPU。MLFQ算法保持B在最高优先级,因为B总是让CPU。如果B是交互型工作,MLFQ就进一步实现了它的目标,让交互型工作快速运行。
    
     
    
    1. 现在,MLFQ在长时间任务之间可以公平地分享CPU,又能给短工作或交互型工作很好地响应时间。这样就完美呢?其实还有问题

      a. 饥饿问题(starvation)问题。即:系统有许多交互型工作,就会不停地抢占长时间任务地CPU,让它们永远无法得到CPU

      b. 愚弄调度程序(game the scheduler)。即:进程在时间片用完之前,调用一个I/O操作(比如访问一个无关的文件),从而主动释放CPU。如此便可以保持吃在高优先级,占用更多的CPU时间

      c. 一个程序可能在不同时间表现不同。即:一个计算密集型的进程可能在某段时间表现为一个交互型的进程

    • 如何提高优先级(2)?

      1. 如何解决上述5中的问题?

        周期性地提升所有任务地优先级。最简单的就是周期性的将所有任务放到最高优先级队列中

        规则5:经过一段时间S,就将系统的任务重新加入到最高优先级队列中。

      2. 新规则解决的问题

        (1)进程不会饿死——在最高优先级队列中,它会以RR的方式,和其他高优先级工作分享CPU,从而最终获得执行

        (2)如果一个CPU密集型工作变成了交互型,当它的优先级提升,调度程序会正确对待它

      3. 下边有两张图,左边没有优先级提升,长时间任务在两个短任务到达后被饿死。右边的每隔50ms就有一次优先级提升(50ms只是举例),因此至少保证了长任务的工作会有一定的进程,每过50ms就被提升到最高优先级,从而定期获得执行。

        操作系统导论(2)_第8张图片

      4. 剩余问题

        (1)S的值如何设置?如果S设置得太高,长任务会被饿死,如果太低,交互型工作得不到合适的CPU时间比例

        (2)如何阻止调度程序被愚弄?工作在时间片以内释放CPU就保留它的优先级是存在问题的

    • 选择好的计时方式

      1. 更完善的CPU计时方式:调度程序应该记录一个进程在某一层消耗的总时间,只要进程用完了自己的配额,就将它降到低一级的优先级队列中。
      2. 重写规则4a和4b

        规则4:一旦工作用完了其在某一层的时间配额(无论中间主动放弃了多少次的CPU),就降低其优先级(移入低一级队列)

      3. 下图对比了在规则4a、4b的策略下(左图),以及在新的规则4(右图)的策略下,同样试图愚弄调度程序的进程的表现。灭有规则4的保护下,进程可以在每个时间片结束前发起一次I/O操作,从而垄断CPU时间,有了这样的保护,无论进程的I/O行为如何,都会慢慢降低优先级

        操作系统导论(2)_第9张图片

    • MLFQ调优以及其他问题

      问题:

      (1)配置多少队列

      (2)每一层队列的时间片配置多大

      这些问题没有显而易见的答案,只有利用对工作负载的经验以及后续对调优程序的调优,才会取得令人满意的平衡

      例如:高优先级队列通常只有较短的时间片,使得交互型工作能够更快的切换。而低优先级队列中更多的是CPU密集性工作,配置更长的时间片会更好

    • MLFQ规则小结

      (1)规则1:如果A的优先级>B的优先级,运行A(不运行B)

      (2)规则2:如果A的优先级=B的优先级,轮转运行A和B

      (3) 规则3:任务进入系统时,放在最高优先级(最上层队列)

      (4)规则4:一旦工作用完了其在某一层的时间配额(无论中间主动放弃了多少次的CPU),就降低其优先级(移入低一级队列)

      (5)规则5:经过一段时间S,就将系统的任务重新加入到最高优先级队列中。

    你可能感兴趣的