各种调度算法的学习思路:
- 算法思想
- 算法规则
- 这种调度算法是用于作业调度还是进程调度
- 抢占式?非抢占式?
- 优点和缺点
- 是否会导致饥饿(某进程/作业长期得不到服务)
一、先来先服务(FCFS,First Come First Serve)
1. 算法思想
主要从“公平”的角度考虑(排队买东西)
2. 算法规则
按照作业/进程到达的先后顺序进行服务
3. 用于作业/进程调度
用于作业调度时,考虑的是哪个作业先到达后备队列:用于进程调度时,考虑的是哪个进程先到达就绪队列
4. 是否可抢占?
非抢占式
5. 优缺点
优点:公平、算法实现简单
缺点:排在长作业(进程)后面的短作业需要等待很长的事件,带权周转事件很大,对短作业来说用户体验不好。即,FCFS算法对长作业有利,对短作业不利(排队买奶茶)
6. 是否会导致饥饿?
不会
我们用一个例题来理解FCFS算法:
各进程到达就绪队列的时间、需要的运行时间如下表所示。使用先来先服务调度算法,计算各进程的等待时间、平均等待时间、周转时间、带权周转时间、平均带权周转时间。
先来先服务调度算法:按照到达的先后顺序调度,事实上就是等待时间越久的越优先得到服务。
调度顺序:P1 -> P2 -> P3 -> P4
周转时间 = 完成时间 - 到达时间
p1 = 7 - 0 = 7; p2 = 11 - 2 = 9; p3 = 12 - 4 = 8; p4 = 16 - 5 = 11
带权周转时间 = 周转时间 / 运行时间
p1 = 7 / 7 = 1; p2 = 9 / 4 = 2.25; p3 = 8 / 1 = 8; p4 = 11 / 4 = 2.75
等待时间 = 周转时间 - 运行时间
p1 = 7 - 7 = 0; p2 = 9 - 4 = 5; p3 = 8 - 1 = 7; p4 = 11 - 4 = 7
注意:本例中的进程都是纯计算行的进程,一个进程到达后要么在等待,要么在运行。如果又有计算、又有I/O操作的进程,其等待时间就是周转时间 - 运行时间 - I/O操作时间
平均周转时间 = (7 + 9 + 8 + 11)/ 4 = 8.75;
平均带权周转时间 = (1 + 2.25 + 8 + 2.75)/ 4 = 3.5
平均等待时间 = (0 + 5 + 7 + 7)/ 4 = 4.75
二、短作业优先(SJF,Shortest Job First)
1. 算法思想
追求最少的平均等待时间,最少的平均周转时间,最少的平均带权周转时间
2. 算法规则
最短的作业/进程优点得到服务(指要求服务时间最短)
3. 用于作业/进程调度
既可用于作业调度,也可用于进程调度。用于进程调度时称为“短进程优先算法(SPF,Shortest Process First)”
四、是否可抢占?
SJF和SPF是非抢占式的算法。但是也有抢占式的版本——最短剩余优先算法(SRTN)
5. 优缺点
优点:“最短的”平均等待时间、平均周转时间
缺点:不公平。对短作业有利,对长作业不利。可能产生饥饿现象。另外,作业/进程的运行是由用户提供的,并不一定真实,不一定能做到真正的短作业优先。
6. 是否会导致饥饿?
会。如果源源不断地有短作业/进程到来,可能使长作业/进程长时间得不到服务,产生“饥饿”现象。如果一直得不到服务,则称为“饿死”。
依旧是上面这个题目,但如果我们使用非抢占式
的短作业优先调度
算法来计算,每次调度时选择当前已到达且运行时间最短的作业/进程。
调度顺序为:P1 -> P3 -> P2 -> P4
周转时间 = 完成时间 - 到达时间
p1 = 7 - 0 = 7; p3 = 8 - 4 = 4; p2 = 12 - 2 = 10; p4 = 16 - 5 = 11
带权周转时间 = 周转时间 / 运行时间
p1 = 7 / 7 = 1; p3 = 4 / 1 = 4; p32= 10 / 4 = 2.5; p4 = 11 / 4 = 2.75
等待时间 = 周转时间 - 运行时间
p1 = 7 - 7 = 0; p2 = 4 - 1 = 3; p3 = 10 - 4 = 6; p4 = 11 - 4 = 7
平均周转时间 = (7 + 4 + 10 + 11)/ 4 = 8
平均带权周转时间 = (1 + 4 + 2.5 + 2.75)/ 4 = 2.56
平均等待时间 = (0 + 3 + 6 + 7)/ 4 = 4
对比FCFS算法的结果,显然SPF算法的平均等待/周转/带权周转时间都要更低
如果使用抢占式
的短作业优先调度
算法(最短剩余时间优先算法)计算。
最短剩余时间优先算法
:每当有进程加入就绪队列改变时就需要调度
,如果新到达的进程剩余时间比当前运行的进程剩余时间
更短,则由新进程抢占
处理机,当前进程重新回到就绪队列。另外,当一个进程完成时也需要调度
。
需要注意的是,当有新进程到达时就绪队列就会改变,就要按照伤处规则进行检查。一下Pn(m)表示当前Pn进程剩余时间为m。各个时刻的情况如下:
- 0时刻(P1到达):
P1(7)
- 2时刻(P2到达):P1(5)、
P2(4)
- 4时刻(P3到达):P1(5)、P2(2)、
P3(1)
- 5时刻(P3完成且P4刚好到达):P1(5)、
P2(2)
、P4(4) - 7时刻(P2完成):P1(5)、
P4(4)
- 11时刻(P4完成):
P1(5)
周转时间 = 完成时间 - 到达时间
p1 = 16 - 0 = 16; p2 = 7 - 2 = 5; p3 = 5 - 4 = 1; p4 = 11 - 5 = 6
带权周转时间 = 周转时间 / 运行时间
p1 = 16 / 7 = 2.28; p2 = 5 / 4 = 1.25; p3 = 1 / 1 = 2; p4 = 6 / 4 = 1.5
等待时间 = 周转时间 - 运行时间
p1 = 16 - 7 = 9; p2 = 5 - 4 = 1; p3 = 1 - 1 = 0; p4 = 6 - 4 = 2
平均周转时间 = (16 + 5 + 1 + 6)/ 4 = 7
平均带权周转时间 = (2.28 + 1.25 + 1 + 1.5)/ 4 = 1.5
平均等待时间 = (9 + 1 + 0 + 2)/ 4 = 3
对比非抢占式短作业优先算法,显然抢占式的这几个指标又要更低。
我们对FCFS和SJF两种算法进行思考
FCFS算法是在每次调度的时候选择一个等待时间最长的作业(进程)为其服务。但是没有考虑到作业的运行时间,因此导致了对短作业不友好的问题。
SJF算法是选择一个执行时间最短的作业为其服务。但是又完全不考虑各个作业的等待时间,因此导致了对长作业不友好的问题,甚至还会造成饥饿问题。
如果我们对这两种算法进行综合,得到的新算法就可以解决他们的问题,也就是高响应比优先算法
。
三、高响应比优先算法
1. 算法思想
要综合考虑作业/进程的等待时间和要求服务的时间
2. 算法规则
在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务
响应比 = (等待时间+要求等待时间)/ 要求等待时间 >=1
3. 用于作业。进程调度
既可用于作业调度。也可用于进程调度
4. 是否可抢占?
非抢占式的算法,因此只要当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算机响应比
5. 优缺点
综合考虑了等待时间和运行时间(要求服务时间)。等待时间相同时,要求服务时间短的优先(SJF特点);要求等待时间相同时,等待时间长的优先(FCFS的优点)。对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长时间饥饿的问题。
6.是否会导致饥饿?
会
使用高响应比优先算法来计算。
非抢占式
算法,只有当前运行的进程主动放弃CPU
时(正常/异常完成,或主动阻塞),才需要进行调度,调度时计算所有就绪进程的响应比
,最高的上处理机
。
- 0时刻:只有P1到达就绪队列,P1上处理机
- 7时刻(P1主动放弃CPU):就绪队列中有P2((5+4)/4=2.25)、P3((3+1)/3=3)、P4((2+4)/4=1.5)
- 8时刻(P3完成):P2(2.5)、P4(1.75)
- 12时刻(P2完成):就绪队列中只有P4
四、时间片轮转(RR,Round-Robin)
1. 算法思想
公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应。
2. 算法规则
按照各进程到达就绪队列地顺序,轮流让各个进程进程执行一个时间片(如100ms)。若进程尾在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队。
3. 用于作业/进程调度
用于进程调度(只有作业放入内存建立了相应的进程后,才能被分配处理机时间片)。
4. 是否可抢占?
若进程未能在时间片内运行完,将被强行剥夺处理机使用权,因此时间片轮转调度算法属于抢占式的算法。由时钟装置发出时钟中断来通知CPU时间片已到。
5. 优缺点
- 优点:公平;响应快,适用于分时操作系统;
- 缺点:由于高频率的进程切换,因此有一定开销;不区分任务的紧急程度。
6. 是否会导致饥饿?
不会
我们通过一个例子来看看:
各进程到达就绪队列的时间、需要的运行时间表如下。使用时间片轮转调度算法,分析时间片大小分别是2、5时的进程运行情况。
时间片轮转调度算法:轮流让就绪队列中的进程依次执行一个时间片(每次选择的都是排队在就绪队列队头的进程)
时间片大小为2
(以下括号内表示当前时刻就绪队列中的进程、进程的剩余运行时间)
- 0时刻(
P1(5)
):0时刻只有P1到达就绪队列,让P1上处理机运行一个时间片 - 2时刻(
P2(4)->P1(3)
):2时刻P2到达就绪队列,P1运行完一个时间片,被剥夺处理机,重新放到队尾。 - 此时P2排在队头,因此让P2上处理机(注意:2时刻,P1下处理机,同一时刻新进程P2到达,如果在题目中遇到这种情况,默认新到达的进程先进入就绪队列)
- 4时刻(
P1(3)->P3(1)->P2(2)
):4时刻,P3到达,先插入到就绪队尾,紧接着,P2下处理机也插入到队尾 - 5时刻(
P3(1)->P2(2)->P4(6)
):5时刻,P4到达插到就绪队尾(由于P1的时间片还没用完,因此暂时不调度。另外,此时P1处于运行态,并不在就绪队列) - 6时刻(P3(1)->P2(2)->P4(6)->P1(1)):6时刻,P1时间片用完,下处理机,重新放回就绪队列,发生调度
- 7时刻(P2(2)->P4(6)->P1(1)):虽然P3的时间片没用完,但是由于P3只需要运行1个单位的时间,运行完了会主动放弃处理机,因此也会发生调度。队头进程P2上处理机。
- 9时刻(P4(6)->P1(1)):进程P2时间片用完,并刚好运行完,发生调度,P4上处理机。
- 11时刻(P1(1)->P4(4)):P4时间片用完,重新回到就绪队列。P1上处理机。
- 12时刻(P4(4)):P1运行完,主动放弃处理机,此时就绪队列中只剩P4,P4上处理机
- 16时刻:所有进程运行结束
时间片大小为5
- 0时刻(
P1(5)
):只有P1到达,P1上处理机 - 2时刻(
P2(4)
):P2到达,但P1时间片尚未结束,因此暂不调度 - 4时刻(
P2(4)->P3(1)
):P3到达,但P1时间片尚未结束。发生调度,P2上处理及 - 5时刻(
P2(4)->P3(1)->P4(6)
):P4运行结束,同时,P1运行结束。发生调度,P2上处理机 - 9时刻(
P3(1)->P4(6)
):P2运行结束,虽然时间片没用完,但是会主动放弃处理机。发生调度 - 10时刻(
P4(6)
):P3运行结束,虽然时间片没用完,三十会主动放弃处理机。发生调度 - 15时刻():P4时间片用完,但是就绪队列为空,因此会让P4继续执行一个时间片
- 16时刻():P4运行完,主动放弃处理机。所有进程运行完
如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮状调度算法退化为
先来先服务算法
,并且会增大进程响应时间
。因此时间片不能太大
。
另一方面,进程调度、切换是有时间代价的(保存、恢复运行环境),因此如果时间片太小
,会导致进程切换过于频繁
,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。可见时间片也不能太小
。