在操作系统中存在多种调度算法,其中有的调度算法适用于作业调度,有的调度算法适用于进程调度,有的调度算法两者都适用。
先来先服务(FCFS)调度算法
FCFS调度算法是一种最简单的调度算法,该调度算法既可以用于作业调度也可以用于进程调度。在作业调度中,算法每次从后备作业队列中选择最先进入该队列的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。
在进程调度中,FCFS调度算法每次从就绪队列中选择最先进入该队列的进程,将处理机分配给它,使之投入运行,直到完成或因某种原因而阻塞时才释放处理机。
下面通过一个实例来说明FCFS调度算法的性能。假设系统中有4个作业,它们的提交时间分别是8、8.4、8.8、9,运行时间依次是2、1、0.5、0.2,系统釆用FCFS调度算法,这组作业的平均等待时间、平均周转时间和平均带权周转时间见如下表:
平均等待时间: t = (0 + 1.6 + 2.2 + 2.5)/4=1.575
平均周转时间: T = (2 + 2.6 + 2.7 + 2.7)/4=2.5
平均带权周转时间: W = (1 + 2.6 + 2.7/0.5 + 2.7/0.2)/4=5.625
FCFS调度算法属于不可剥夺算法。从表面上看,它对所有作业都是公平的,但若一个长作业先到达系统,就会使后面许多短作业等待很长时间,因此它不能作为分时系统和实时系统的主要调度策略。但它常被结合在其他调度策略中使用。例如,在使用优先级作为调度策略的系统中,往往对多个具有相同优先级的进程按FCFS原则处理。
FCFS调度算法的特点是算法简单,但效率低;对长作业比较有利,但对短作业不利(相对SJF和高响应比);有利于CPU繁忙型作业,而不利于I/O繁忙型作业。
短作业优先(SJF)调度算法
短作业(进程)优先调度算法是指对短作业(进程)优先调度的算法。短作业优先(SJF)调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法,则是从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即执行,直到完成或发生某事件而阻塞时,才释放处理机。
例如,给出的一组作业,若系统釆用短作业优先调度算法,其平均等待时间、平均周转时间和平均带权周转时间见如下表:
平均等待时间: t = (0 + 2.3 + 1.4 + 1)/4=1.175
平均周转时间: T = (2 + 3.3 + 1.9 + 1.2)/4=2.1
平均带权周转时间: W = (1 + 3.3 + 3.8 + 6)/4=3.525
JF调度算法也存在不容忽视的缺点:
1.该算法对长作业不利,SJF调度算法中长作业的周转时间会增加。更严重的是,如果有一长作业进入系统的后备队列,由于调度程序总是优先调度那些 (即使是后进来的)短作业,将导致长作业长期不被调度(“饥饿”现象,注意区分“死锁”。后者是系统环形等待,前者是调度策略问题)。
2.该算法完全未考虑作业的紧迫程度,因而不能保证紧迫性作业会被及时处理。
3.由于作业的长短只是根据用户所提供的估计执行时间而定的,而用户又可能会有意或无意地缩短其作业的估计运行时间,致使该算法不一定能真正做到短作业优先调度。
注意,SJF调度算法的平均等待时间、平均周转时间最少。
高响应比优先调度算法
高响应比优先调度算法主要用于作业调度,该算法是对FCFS调度算法和SJF调度算法的一种综合平衡,同时考虑每个作业的等待时间和估计的运行时间。在每次进行作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行。
响应比的变化规律可描述为:
根据公式可知:
1.当作业的等待时间相同时,则要求服务时间越短,其响应比越高,有利于短作业。
2.当要求服务时间相同时,作业的响应比由其等待时间决定,等待时间越长,其响应比越高,因而它实现的是先来先服务。
3.对于长作业,作业的响应比可以随等待时间的增加而提高,当其等待时间足够长时,其响应比便可升到很高,从而也可获得处理机。克服了饥饿状态,兼顾了长作业。
时间片轮转调度算法
时间片轮转调度算法主要适用于分时系统。在这种算法中,系统将所有就绪进程按到达时间的先后次序排成一个队列,进程调度程序总是选择就绪队列中第一个进程执行,即先来先服务的原则,但仅能运行一个时间片,如100ms。在使用完一个时间片后,即使进程并未完成其运行,它也必须释放出(被剥夺)处理机给下一个就绪的进程,而被剥夺的进程返回到就绪队列的末尾重新排队,等候再次运行。
在时间片轮转调度算法中,时间片的大小对系统性能的影响很大。如果时间片足够大,以至于所有进程都能在一个时间片内执行完毕,则时间片轮转调度算法就退化为先来先服务调度算法。如果时间片很小,那么处理机将在进程间过于频繁切换,使处理机的开销增大,而真正用于运行用户进程的时间将减少。因此时间片的大小应选择适当。
时间片的长短通常由以下因素确定:系统的响应时间、就绪队列中的进程数目和系统的处理能力。
优先级调度算法
优先级调度算法又称优先权调度算法,该算法既可以用于作业调度,也可以用于进程调度,该算法中的优先级用于描述作业运行的紧迫程度。
在作业调度中,优先级调度算法每次从后备作业队列中选择优先级最髙的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中,优先级调度算法每次从就绪队列中选择优先级最高的进程,将处理机分配给它,使之投入运行。
而根据进程创建后其优先级是否可以改变,可以将进程优先级分为以下两种:
(1).静态优先级。优先级是在创建进程时确定的,且在进程的整个运行期间保持不变。确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
基于静态优先级的调度算法实现简单,系统开销小,但由于静态优先级一旦确定以后,直到执行结束为止始终保持不变,从而系统效率较低,调度性能不高。
(2).动态优先级。在进程运行过程中,根据进程情况的变化动态调整优先级。动态调整优先级的主要依据为进程占有CPU时间的长短、就绪进程等待CPU时间的长短。
进程的动态优先级一般根据以下原则确定:
1).根据进程占用CPU时间的长短来确定。一个进程占有处理机的时间愈长,则在被阻塞之后再次获得调度的优先级就越低,反之,其获得调度的可能性就会越大。
2).根据就绪进程等待CPU的时间长短来决定。一个就绪进程在就绪队列中等待的时间越长,则它获得调度选中的优先级就越高。
由于动态优先级随着时间的推移而变化,系统要经常计算各进程的优先级,因此系统要为此付出一定的开销。
线性优先级调度策略:
使用轮转法调度进程时,新创建的进程也放入就绪队列末尾享受平等的处理机时间片,这对于执行时间长的进程来说是有点不公平,因为它们需要多个时间片才能完成。
因此,线性优先级调度策略采用了如下方式,即新创建的进程按FCFS方式排成就绪队列,而其他已得到过时间片服务的进程也按FCFS方式排成另一个就绪队列(或称为享受服务队列)。
对于这两个不同的进程,设新创建进程就绪队列中进程的优先级P以:
的速率增加。另外,享受服务队列进程的优先级P以:
的速率增长。设某一进程在时刻t1时被创建,在时刻t时,该进程的优先级为:
又设该进程t’1时刻转入享受服务队列,则在时刻t,该进程的优先级变为:
那么,一个新创建进程等待多长时间之后进入享受服务队列较为合适呢?
当新创建进程就绪队列中的头一个进程的优先级P(t)=a(t-t1)与享受服务队列中最后一个就绪进程的优先级P(t)=bt相等时,新创建进程队列中的头一个进程可以转入享受服务进程队列。其优先级变化曲线为:
但享受服务进程队列为空时,新创建队列的头一个进程也将移入享受服务进程队列。
在线性优先级调度算法中,a>b>0的条件是必要的。否则,当b>a>0时,两个不同队列的就绪态进程的优先级将永远不会相等,从而,在享受服务进程队列中永远只有一个进程,上述的线性优先级调度策略退回到FCFS方式。
如果a>b=0,则线性优先级调度策略退回到轮转法调度方式。事实上,线性优先级调度策略是一种介于轮转法和FCFS方式之间的调度策略。
根据新的更高优先级进程能否抢占正在执行的进程,可将该调度算法分为:
(1).非剥夺式优先级调度算法。当某一个进程正在处理机上运行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在运行的进程继续运行,直到由于其自身的原因而主动让出处理机时(任务完成或等待事件),才把处理机分配给更为重要或紧迫的进程。
(2).剥夺式优先级调度算法。当一个进程正在处理机上运行时,若有某个更为重要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。
多级反馈队列调度算法(集合了前几种算法的优点)
多级反馈队列调度算法是时间片轮转调度算法和优先级调度算法的综合和发展,如图所示。通过动态调整进程优先级和时间片大小,多级反馈队列调度算法可以兼顾多方面的系统目标。例如,为提高系统吞吐量和缩短平均周转时间而照顾短进程;为获得较好的I/O设备利用率和缩短响应时间而照顾I/O型进程;同时,也不必事先估计进程的执行时间。
多级反馈队列调度算法的实现思想如下:
(1).应设置多个就绪队列,并为各个队列赋予不同的优先级,第1级队列的优先级最高,第2级队列次之,其余队列的优先级逐次降低。
(2).赋予各个队列中进程执行时间片的大小也各不相同,在优先级越高的队列中,每个进程的运行时间片就越小。例如,第2级队列的时间片要比第1级队列的时间片长一倍,…..第i+1级队列的时间片要比第i级队列的时间片长一倍。
(3).当一个新进程进入内存后,首先将它放入第1级队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第2级队列的末尾,再同样地按FCFS 原则等待调度执行;如果它在第2级队列中运行一个时间片后仍未完成,再以同样的方法放入第3级队列….如此下去,当一个长进程从第1级队列依次降到第n级队列后,在第n级队列中便釆用时间片轮转的方式运行。
(4).仅当第1级队列为空时,调度程序才调度第2级队列中的进程运行;仅当第1~(i-1)级队列均为空时,才会调度第i级队列中的进程运行。如果处理机正在执行第i级队列中的某进程时,又有新进程进入优先级较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i级队列的末尾,把处理机分配给新到的更高优先级的进程。
多级反馈队列的优势有:
终端型作业用户:短作业优先。
短批处理作业用户:周转时间较短。
长批处理作业用户:经过前面几个队列得到部分执行,不会长期得不到处理。
例子1
通过一个多道编程的具体例子,来看看多道编程时计算机里面事件的发生顺序和多道编程环境下系统响应时间的提升。
假定我们有4个程序,每个程序花费80%的时间进行I/O,20%的时间使用CPU,每个程序的启动时间和其需要使用CPU进行计算机的分钟数如表4-1所示:
(1).从0点0分开始到0点10分,系统里只有1个程序,因此属于单道编程状态。单道编程时CPU的利用率为20%,因此第1个程序在该10分钟里总共使用了CPU达2分钟(其他8分钟都用来进行I/O了)。
(2).0点10分到0点15分,系统里面有两个程序,因此属于2道编程。2道编程时CPU利用率为36%,则在5分钟时间内,CPU使用了1.8分钟。假定这两个程序完全平等,则每个程序使用CPU的时间是0.9分钟。至此,程序1总共运行了2.9分钟CPU时间,程序2运行了0.9分钟CPU时间。
(3).从0点15分开始到0点20分,系统里面有3个程序,因此属于3道编程状态。3道编程时CPU的利用率为48.8%,则在这5分钟时间内,CPU被占用了大约2.4分钟(其他2.6分钟都用来I/0了)。同样,假定所有程序完全平等,则每个程序使用CPU的时间为0.8分钟。至此,程序1总共运行了3.7分钟CPU时间,程序2运行了1.7分钟CPU时间,程序3运行了0.8分钟CPU时间。此时,程序1离结束所需要的CPU时间最短,仅为0.3分钟。
(4).从0点20分开始,系统里面有4份额程序,因此属于4道编程。我们知道4道编程时CPU利用率为59%而如果程序1想再运行0.3分钟CPU时间,则整个系统需运行时间约为2分钟(2分钟时间内CPU共被使用1.2分钟,平均每个程序使用CPU时间为0.3分钟)因此在0点22分时,第一个程序执行完毕,系统变为3道编程。
(5).程序1结束,程序2总共运行了2分钟CPU时间,程序3运行了1.1分钟CPU时间,程序4运行了0.3分钟CPU时间。此时,程序3离所需的CPU时间最短,为0.9分钟。那么系统需要运行多长时间才能使程序3获得0.9分钟的CPU时间呢?答案是5.6分钟。因为3道编程的CPU利用率大约为48%,而5.6分钟内CPU的时间约是2.7分钟。三个程序平分,每个程序运行了0.9分钟CPU时间。因此,到0点27.6分钟,系统里只剩下两个程序。
(6).在1.6分钟后,即0点28.2分钟时,程序2将结束运行,剩下程序4一个程序。该程序则在0点31.7分钟时结束运行。整个事件发生顺序:
多道编程比起单道编程,系统平时响应时间缩短了11.375分钟,响应时间减少了41.37%。多道编程带来的好处到底有多少和每个程序的性质、多道编程的度数、进程切换消耗等有关。但一般说来,只要度数适当,多道编程总是利大于弊。
例子2(腾讯2013年笔试题)
假定我们有3个程序,每个程序花费80%的时间进行I/O,20%的时间使用CPU。每个程序启动时间和其需要使用进行计算的分钟数如下,不考虑进程切换时间。
程序编号 启动时间 需要CPU时间(分钟)
1 00:00 3.5
2 00:10 2
3 00:15 1.5
请问在多线程/进程环境下,系统的总响应时间是()
A.22.5 B.23.5 C.24.5 D.25.5
CPU利用率:io处理占总时间比例p。
则多道程序 cpu占用率为1-p^n。
做出的正确结果应该是23.47,也就是答案B。
分析步骤:
0-10分钟的时候,只有一个进程1在运行。
单进程CPU占有率是20%,所以这10分钟内,进程1消耗了2分钟的CPU。进程2是0,进程3也是0
然后在10-15分钟内,有两个进程在运行(1和2),双进程的CPU利用率是36%,所以,这五分钟内,CPU一共利用了1.8分钟,平均分给每个进程,是0.9分钟。
此时,进程1已经占用了CPU 2.9分钟,还需要0.6分钟,这时候有三个进程在运行,所有总的CPU时间需要1.8分钟。
三进程的CPU利用率是48.8%,所以总共需要1.8/0.488=3.69分钟。这时,进程1已经3.5分钟的CPu利用时间利用完了。
此时还剩下2和3号进程在运行。2号进程还需要0.5分钟,所以0.5×2/0.36=2.78,此时2号进程的2分钟CPU时间也利用完了。3号进程还需要0.4分钟的CPU利用时间。0.4/0.2 = 2