调度算法
一、进程调度算法
非抢占式的先来先服务调度算法(First Come First Seved, FCFS)
先来后到,每次从就绪队列选择最先进入队列的进程,然后⼀直运行,直到进程退出或被阻塞,才会继续从队列中选择第⼀个进程接着运行。
FCFS对长作业有利,适用于CPU繁忙型作业的系统,而不适用于I/O繁忙型作业的系统。
最短作业优先调度算法(Shortest Job First, SJF)
它会优先选择运云时间最短的进程来运行,这有助于提高系统的吞吐量。
这显然对长作业不利,很容易造成⼀种极端现象,周转时间变长,致使长作业长期不会被运行。
高响应比优先调度算法(Highest Response Ratio Next, HRRN)
权衡了短作业和长作业,每次进行进程调度时,先计算响应比优先级,然后把响应比优先级最高的进程投入运行。
优先权 = (等待时间 + 要求服务时间) / 要求服务的时间
- 如果两个进程的等待时间相同时,要求的服务时间越短,响应比就越高,这样短作业的进程容易被选中运行
- 如果两个进程要求的服务时间相同时,等待时间越长,响应比就越高,这就兼顾到了长作业进程,因为进程的响应比可以随时间等待的增加而提高,当其等待时间足够长时,其响应比便可以升到很高,从而获得运行的机会
时间片轮转调度算法(Round Robin, RR)
每个进程被分配⼀个时间段,称为时间片,即允许该进程在该时间段中运行
- 如果时间片用完,进程还在运行,那么将会把此进程从CPU释放出来,并把CPU分配给另外⼀个进程
- 如果该进程在时间片结束前阻塞或结束,则CPU立即进行切换
时间片的长度就是⼀个很关键的点
- 如果时间片设得太短会导致过多的进程上下文切换,降低了 CPU 效率
- 如果设得太长可能引起对短作业进程的响应时间变长
时间片设为 20ms~50ms 通常是⼀个比较合理的折中值。
最高优先级调度算法(Highest Priority First,HPF)
选择就绪队列中选择最高优先级的进程进行运行。
进程的优先级可以分为,静态优先级和动态优先级
- 静态优先级:创建进程时候,就已经确定了优先级了,然后整个运行时间优先级都不会变化
- 动态优先级:根据进程的动态变化调整优先级,比如如果进程运行时间增加,则降低其优先级,如果进程等待时间(就绪队列的等待时间)增加,则升高其优先级,也就是随着时间的推移增加等待进程的优先级
该算法也有两种处理优先级高的⽅法,非抢占式和抢占式
- 非抢占式:当就绪队列中出现优先级高的进程,运行完当前进程,再选择优先级高的进程。
- 抢占式:当就绪队列中出现优先级高的进程,当前进程挂起,调度优先级高的进程运⾏。
但是依然有缺点,可能会导致低优先级的进程永远不会运行。
多级反馈队列调度算法(Multilevel Feedback Queue)
时间片轮转算法和最高优先级算法的综合和发展。
- 多级表示有多个队列,每个队列优先级从高到低,同时优先级越高时间片越短。
- 反馈表示如果有新的进程加⼊优先级高的队列时,立刻停止当前正在运行的进程,转而去运行优先级高的队列。
二、内存页面置换算法
在学置换算法之前,先了解一下缺页中断吧!
缺页中断(缺页中断)
当CPU访问的页面不在物理内存时,便会产生一个缺页中断,请求操作系统将所缺页调入到物理内存。那 它与⼀般中断的主要区别在于
- 缺页中断在指令执行期间产生和处理中断信号,而⼀般中断在⼀条指令执行完成后检查和处理中断信号。
- 缺页中断返回到该指令的开始重新执行该指令,而⼀般中断返回回到该指令的下⼀个指令执行。
页表项
- 状态位:用于表示该页是否有效,也就是说是否在物理内存中,供程序访问时参考
- 访问字段:用于记录该页在⼀段时间被访问的次数,供页面置换算法选择出页面时参考
- 修改位:表示该页在调入内存后是否有被修改过,由于内存中的每⼀页都在磁盘上保留⼀份副本,因此,如果没有修改,在置换该页时就不需要将该页写回到磁盘上,以减少系统的开销;如果已经被修改,则将该页重写到磁盘上,以保证磁盘中所保留的始终是最新的副本。
- 硬盘地址:用于指出该页在硬盘上的地址,通常是物理块号,供调入该页时使用。
当我们在内存中找不到空闲页的时候,就需要要页面置换算法了。
最佳页面置换算法
最佳页面置换算法基本思路是,置换在未来最长时间不访问的页面。
所以,该算法实现需要计算内存中每个逻辑页面的下⼀次访问时间,然后比较,选择未来最长时间不访问的页面。
这很理想,但是实际系统中无法实现,因为程序访问页面时是动态的,我们是无法预知每个页面在下⼀ 次访问前的等待时间。 所以,最佳页面置换算法作用是为了衡量你的算法的效率,你的算法效率越接近该算法的效率,那么说明你的算法是高效的。
先进先出置换算法
既然我们无法预知页面在下⼀次访问前所需的等待时间,那我们可以选择在内存驻留时间很长的页面进行中置换,这个就是先进先出置换算法的思想。
最近最久未使用的置换算法
最近最久未使用(LRU)的置换算法的基本思路是,发生缺页时,选择最长时间没有被访问的页面进行置换,也就是说,该算法假设已经很久没有使用的页面很有可能在未来较长的⼀段时间内仍然不会被使用。 这种算法近似最优置换算法,最优置换算法是通过未来的使用情况来推测要淘汰的页面,而 LRU则是通过历史的使用情况来推测要淘汰的页面。
虽然LRU在理论上是可以实现的,但代价很高。为了完全实现LRU,需要在内存中维护⼀个所有页面的 链表,最近最多使用的页面在表头,最近最少使用的页面在表尾。 困难的是,在每次访问内存时都必须要更新整个链表。在链表中找到⼀个页面,删除它,然后把它移动到表头是⼀个非常费时的操作。 所以,LRU虽然看上去不错,但是由于开销比较大,实际应用中比较少使用。
时钟页面置换算法
那有没有⼀种即能优化置换的次数,也能方便实现的算法呢? 时钟页面置换算法就可以两者兼得,它跟LRU近似,又是对FIFO的⼀种改进。
该算法的思路是,把所有的页面都保存在⼀个类似钟面的环形链表中,⼀个表针指向最老的页面。
当发生缺页中断时,算法首先检查表针指向的页面
- 如果它的访问位是0就淘汰该页面,并把新的页面插⼊这个位置,然后把表针前移⼀个位置
- 如果访问位是1就清除访问位,并把表针前移⼀个位置,重复这个过程直到找到了⼀个访问位为0的页面为止
最不常用算法
最不常用(LFU)算法,当发生缺页中断时,选择访问次数最少的那个页面,并将其淘汰。
对每个页面设置⼀个访问计数器,每当⼀个页面被访问时,该页面的访问计数器就累加 1。在发生缺页中断时,淘汰计数器值最小的那个页面。 看起来很简单,每个页面加⼀个计数器就可以实现了,但是在操作系统中实现的时候,我们需要考虑效率和硬件成本的。 要增加⼀个计数器来实现,这个硬件成本是比较高,另外如果要对这个计数器查找哪个页面访问次数最小,查找链表本身,如果链表长度很大,效率不高。LFU算法只考虑了频率问题,没考虑时间的问题,比如有些页面在过去时间⾥访问的频率很高,但是现在已经没有访问了,而当前频繁访问的页面由于没有这些页面访问的次数高,在发生缺页中断时,就会可能会误伤当前刚开始频繁访问,但访问次数还不高的页面。
那这个问题的解决的办法还是有的,可以定期减少访问的次数,比如当发生时间中断时,把过去时间访问的页面的访问次数除以2,也就说,随着时间的流失,以前的高访问次数的页面会慢慢减少,相当于加大了被置换的概率。
三、磁盘调度算法
磁盘调度算法的目的很简单,就是为了提高磁盘的访问性能,⼀般是通过优化磁盘的访问请求顺序来做到的。
先来先服务算法(First-Come,First-Served,FCFS)
先到来的请求,先被服务.
最短寻道时间优先算法(Shortest Seek First,SSF)
优先选择从当前磁头位置所需寻道时间最短的请求,有些磁道永远不会被响应,就产生了饥饿现象,这里产生饥饿的原因是磁头在一小块区域来回移动。
扫描算法(Scan)
寻道时间优先算法会产生饥饿的原因在于:磁头有可能再⼀个小区域内来回得移动。
为了防止这个问题,可以规定:磁头在⼀个方向上移动,访问所有未完成的请求,直到磁头到达该方向上的最后的磁道,才调换方向,这就是扫描算法。
扫描调度算法性能较好,不会产生饥饿现象,但是存在这样的问题,中间部分的磁道会比较占便宜,中间部分相比其他部分响应的频率会比较多,也就是说每个磁道的响应频率存在差异。
循环扫描算法(Circular Scan, CSCAN )
扫描算法使得每个磁道响应的频率存在差异,那么要优化这个问题的话,可以总是按相同的方向进行扫描,使得每个磁道的响应频率基本一致。
循环扫描规定:只有磁头朝某个特定方向移动时,才处理磁道访问请求,而返回时直接快速移动至最靠边缘的磁道,也就是复位磁头,这个过程是很快的,并且返回中途不处理任何请求,该算法的特点,就是磁道只响应一个方向上的请求。
循环扫描算法相比于扫描算法,对于各个位置磁道响应频率相对比较平均。
LOOK算法
针对Scan优化,它的工作方式,磁头在每个方向上仅仅移动到最远的请求位 置,然后立即反向移动,而不需要移动到磁盘的最始端或最末端,反向移动的途中会响应请求。
C-LOOK算法
针对C-Scan优化,它的⼯作方式,磁头在每个方向上仅仅移动到最远的请求位置, 然后立即反向移动,而不需要移动到磁盘的最始端或最末端,反向移动的途中不会响应请求。