上一篇文章我们介绍了的组成、状态及特点,今天这篇文章来介绍进程的调度。
进程线程概念全解析三 - 进程的调度
一篇文字特别多的文章
一、调度的定义
调度的定义:即当我们资源固定时,有很多个并发请求,这个时候执行哪些程序,就需要通过一些算法来进行调度管理。而在操作系统中,调度分为三个层级,分别是高级调度(也称作业调度),中级调度(也称内存调度),低级调度(也称进程调度)。
高级调度,也称作业调度。它是一个按照某种规则,将作业从外存调度到内存的过程,高级调度发生频率最低;
中级调度,也称内存调度。在作业运行过程中,某个时刻可能因为资源不足,会将程序暂时调出内存,此时程序处于挂起状态(需要注意的是,此时进程的 PCB 还是在内存中的)。而从挂起队列中选择合适的进程并将其调入内存就是中级调度。中级高度发生频率中等;
低级调度,也称进程调度。这是操作系统中最基本的调度,即按照某种规则,从就绪队列中选择一个进程并为其分配处理机。低级调度发生频率最高;
下面我们将详细介绍低级调度,也就是进程调度。
二、进程调度的定义目标
在多进程并发的环境里,各进程之间是独立,各自以不可预知的速度和顺序运行的(并发性、独立性、异步性)。我们一直说的是并发,而不是并行,是因为 CPU 个数是有限制的,特别是在早期单个 CPU 的情况下,实际上在任何时刻都只有一个进程处理运行状态,但一段时间内进程是有多个进程“切换着”来执行的,因为这里的“一段时间”极其短,所以感知上认为是有多个进程在“同时”运行。而多个进程“切换着”交替执行,就需要确定什么时候该执行哪个进程,什么时候进程该让出处理机交由别的进程来执行。因此就引入了进程调度的概念。
进程的调度就是操作系统进程管理的一个重要组成部分。其任务是选择下一个要运行的进程
《计算机的心智-操作系统之哲学原理第2版第5章》
那操作系统是怎么管理进程调度的呢?如何管理取决于操作系统管理进程调度的目标,而这个目标对于不同的系统,不同的程序来说又是不一样的。比如对于程序,我们通常会分为三类:
计算密集型,也称之为 CPU 密集型,这一类程序的特点是大部分时间都集中于 CPU 上,仅有少量时间用于 I/O;
I/O密集型,即大部分时间都用来 I/O 操作,比如爬虫程序等;
介于两者之间的程序,即有长时间的 CPU 执行部分,又有长时间的 I/O 部分,称之为平衡程序。
此外,我们还需要了解调度算法评价指标:
周转时间,即作业从提交到完成所需要的时间;
平均周转时间,即作业的周转时间和/作业个数;
带权周转时间,即作业周转时间/作业实际运行时间;
平均带权周转时间,即作业的带权周转时间和/作业个数。
举例说明下周转时间相关指标。比如你排队去买奶茶,从你开始排队,到买到奶茶中间所花的时间,即为周转时间,这中间包括排队等待的时间,而实际作业时间应该是点单到真正拿到奶茶。带权周转时间即整个时间/从点单到真正拿到奶茶这个时间。所以可以知道,作业的带权周转时间越小越好。
吞吐率,即单位时间内处理程序的数量;
利用率,即单位时间内使用时间的占比,比如CPU利用率,即单位时间内CPU执行时间的占比;
响应时间,即从用户提交到第一次响应所花的时间;
等待时间,即进程等待被服务时间,注意 I/0 阻塞等待时间并不包括在内。
其实对于响应时间和周转时间,大体上我认为是差不多的。周转时间通常用于批处理系统下评估算法的性能,因为批处理并不涉及用户交互,只关系实际作业执行的情况,而响应时间通常用于交互式系统,典型的比如用户输入命令行,到实际执行命令并展示结果,整个过程的时间就是响应时间。交互式系统更注意用户体验。
进程调度就是要达到极小化平均响应时间,极大化系统吞吐率,保持系统各个功能部件均处于繁忙状态和提供某种“看上去公平”的机制。说白了,就是希望作业执行得越快越少,单位时间内完成的作业越多越好,各个功能部件利用率越高越好。而公平,就是让各个程序在调度时是平等的,都是有可能会被执行的。为了达到这些目标,设计了很多的进程调度算法,下面将分别介绍这些调度算法。
三、进程调度算法
上面,我们提到了评估调度算法的一些指标,除了这些指标外,还有一些其他评估调度算法的概念:
是否为抢占式算法。调度算法分为非抢占式与抢占式,从字面意思就很好理解,即当有新进程到达时,根据算法,如果有别的进程比当前运行进程更符合条件,是否强制“替换”当前进程。如果强制“替换”当前进程(即当前进程重新进入就绪队列),即为抢占式,否则为非抢占式;
是否会出现进程饥饿。即是否会出现有进程永远得不到执行,好的调度算法,应该是需要避免出现这种情况的。
在了解这些概念之后,下面我们来介绍下几个调度算法:
先来先服务调度算法(FCFS,First Come First Serve)
这个算法很简单,就是谁先来,就先服务谁。这种规则就和我们排队比较像(当然如果没人插队的话)。这个算法的优点就是简单,易于理解,缺点就是有些短的工作可能会变得很慢,因为可能它运气不好,前面有很长的工作比它先到。
时间片轮转算法(RR,Round-Robin)
时间片轮转算法是对 FCFS 算法的一种改进,其主要目的是改善上述先来先服务调度算法存在的问题,使得当短程序排在长程序后面时也有机会很快得到执行。这个算法也很好理解,即当程序每执行多长时间就让出 CPU。这个算法的优点是看上去很“公平”,也使先来先服务中的缺点在一定程序上得到了改善,但缺点是这个时间片的选择很难把控,如果过大,就越来越像 FCFS,但如果过短,会造成大量的进程切换,使系统消耗增大。
时间片的选择需要考虑几个因素。首先,我们需要知道进行一次进程切换所需要耗费的 CPU 时间,以及我们可以接受的整个系统的消耗范围。比如每次进程切换需要消耗 0.1 毫秒的 CPU 时间,而我们可以承受的 CPU 浪费为 1%,那说明在整个时间片内,切换所占的消耗为 1%,因此所能承受的浪费 = 切换浪费的时间 / 时间片,也就是说此时选择 10 毫秒的时间片就很合理。此外,还需要考虑有多少进程在系统里运行,如果运行的进程多,时间片就需要短一些。
需要注意的是,时间片轮转看上去非常公平,每个进程周期性地获得 CPU 时间,但它的系统响应时间不一定总是比 FCFS 的响应时间短。比如 A 程序运行需要 100s,B 程序需要 1s,如果使用 FCFS,在最优情况下,B比A先到,则B的响应时间为 1s,A的响应时间为 101s,系统的平均响应时间为 51s。而使用时间片轮转,除非时间片的选择是 1s,否则时时间片轮转的系统响应时间将比 FCFS 慢,因为进程切换还需要消耗时间。
短任务优先算法(STSF,Shorted Time to Completion First)
上面我们一直说,时间片轮转是一个“看上去很公平”的调度算法,为什么说是”看上去呢“,因为如果当每个人能力一样时,这样固定时间片轮转是很公平的,但在程序执行时,每个程序的”能力”并不完全一样。因此又有另外一种改善短任务排在长任务后面轮转而造成响应时间和交互体验下降的办法,即短任务优先。
这个算法也很好理解,就是短任务的优先级比长任务高。短任务优先算法分为抢占式与非抢占式(注意,先来先服务是非抢占的,而时间片是抢占式的),非抢占短任务优先算法的原理是让已在 CPU 上运行的程序执行到结束或阻塞,然后在所有候选的程序中选择需要执行时间最短的进程来执行。抢占式短任务优先算法则是每增加一个新的进程就需要对所有进程(包括正式 CPU 上运行的进程)进行检查,谁的时间短,就运行谁。
短任务优先算法的优点在于,在某些情况下比时间片轮转要好,解决了短任务排在长任务后的响应时间过长的问题。但缺点在于,程序执行时间的长短是不可预知的,通常是用户自己提交的,这个提交的过程是可以“造假”的。此外,短任务优先是可能造成“饥饿”现象的,在抢占式的短任务执行算法中,如果一直有执行时间更短的任务提交,则长任务就一直不能被执行。
2.4 优先级调度算法
优先级调度算法就是为了解决短任务优先算法中,程序执行时长不可预知的问题。程序优先级可静态或动态的设定。静态优先级,即程序优先级在运行后就是固定的,其实在一定程度上和短任务优先就比较类似了(因为程序的执行时间也是用户自己提交的);动态优先级则可以更好的避免这个问题,我们可以通过一些规则,动态的去调整任务的优先级,比如:
系统进程高于用户进程;
I/O 密集型的任务优先级要尽可能高,因为它越先执行,就越先进行 I/O 等待,而在等待的过程又可以执行其他任务,这样不仅提高了各个部件的利用率,也减少了响应时间;
等待了很长时间的任务可以提高优先级,这样可以减少出现“饥饿”现象的概率;
被频繁调度过的程序可适当减少优先级,这样可以给别的进程提供可以运行的机会,减少出现“饥饿”现象的概率。
优先级调度算法的优点是可以赋予重要的进程以高优先级以确保重要任务能够得到 CPU 时间,而且动态优先级调度,可以减少出现“饥饿”现象的概率,但并不能完全保证不出现“饥饿”现象,如果有源源不断的高优先级进程出现,则还是可能出现“饥饿”现象。而它的缺点则是作业的响应时间不能保证,除非将一个进程的优先级设置为最高,但如果每个人都将自己进程的优先级设为最高,则响应时间还是无法保证。
2.5 混合调度算法
上面说的调度算法都各有利弊,因此有一种混合调度算法,对这些算法做了综合。它主要的思想在于首先基于优先级,将优先级分为几个大类,但在每个小类里使用时间片轮转,且优先级高的时间片设置小一点,优先级低的,时间片设置大一点,当任务从高优先级里被调度后,如果还没有完成,则会被放入下一个优先级类别中,当上一个高优先级没有任务执行了,则会开始调度下一个优先级类中的任务。简单过程如下:
首先分为多级就绪队列,优先级按从高到低,时间片按从小到大
当进程进入时,首先进入高优先级队列,且按先来先服务的调度算法进行时间片的分配
当进程时间片执行完后,进程还未执行完毕,则将进程放入下一级队列的队尾
当第 k 级进程执行完后,才开始对 k+1 级队列进行时间片的分配
所以,可以看到,混合调度实际是结合了先来行服务、优先级调度以及时间片轮转三种调度算法。
进程调度算法远不止上面介绍的几种,比如还有保障调度算法、彩票调度算法,还有实时系统中的实时调度算法等。
四、总结
五、参考资料
《计算机的心智-操作系统之哲学原理第2版》
b站王道考研 - 操作系统