进程调度算法
操作系统有三大调度机制,分别是进程调度、内存页面置换和磁盘调度算法。
进程调度算法
定义
进程调度算法也称 CPU 调度算法,毕竟进程是由 CPU 调度的,当 CPU 空闲时,操作系统就选择内存中的某个「就绪状态」的进程,并给其分配 CPU。
进程的状态
在一个进程的活动期间至少具备三种基本状态,即运行状态、就绪状态、阻塞状态。为什么说至少呢?当然,进程还有另外两个基本状态:创建状态和结束状态。
- 创建状态(new):进程正在被创建;
- 就绪状态(Ready):可运行,由于其他进程处于运行状态而暂时停止运行;
- 运行状态(Running):该时刻进程占用 CPU;
- 阻塞状态(Blocked):该进程正在等待某一事件发生(如等待输入/输出操作的完成)而暂时停止运行,这时,即使给它CPU控制权,它也无法运行;
- 结束状态(Exit):进程正在从系统中消失时的状态;
状态转移过程:
- NULL -> 创建状态:创建一个新进程的初始状态;
- 创建状态 -> 就绪状态:当进程被创建完成并初始化后,一切就绪准备运行时,变为就绪状态,进入就绪队列,等待被CPU调度。
- 就绪状态 -> 运行状态:处于就绪队列中的进程被操作系统的进程调度器选中后,就分配给 CPU, 正式运行该进程;
- 运行状态 -> 结束状态:当进程已经运行完成或出错时,会被操作系统作结束状态处理,操作系统得从就绪队列选择另外一个进程运行;
- 运行状态 -> 就绪状态:处于运行状态的进程在运行过程中,由于分配给它运行的时间片用完了,操作系统会把该进程变为就绪态,接着从就绪态选中另外一个进程运行;
- 运行状态 -> 阻塞状态:当进程请求某个事件且必须等待时,例如请求 I/O 事件,此时操作系统必须选择另外一个进程运行;
- 阻塞状态 -> 就绪状态:当进程要等待的事件完成时,它从阻塞状态变到就绪状态;
在虚拟内存管理的操作系统中,通常会把阻塞状态的进程的物理内存空间换出到硬盘,等需要再次运行的时候,再从硬盘换入到物理内存。这么做,可以使得阻塞状态的进程不会暂用物理内存空间,毕竟物理内存空间是有限的,被阻塞状态的进程占用着物理内存是一种浪费物理内存的行为。
此外,进程还有一个状态来描述进程没有占用实际的物理内存空间:挂起状态,该状态又可细分为两种:
- 阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现;
- 就绪挂起状态:进程在外存(硬盘),但只要进入内存,立刻运行;
导致进程挂起的原因不只是因为进程所使用的内存空间不在物理内存,还包括如下情况:
- 通过 sleep 让进程间歇性挂起,其工作原理是设置一个定时器,到期后唤醒进程。
- 用户希望挂起一个程序的执行,比如在 Linux 中用
Ctrl+Z
挂起进程;
什么叫调度
选择一个进程占用着 CPU 在运行,称为调度。
什么时候会调度
在进程的生命周期中,当进程从一个运行状态切换为另一状态时,就会触发一次调度。
比如以下几种状态转换时会触发 CPU 调度:
- 就绪状态 -> 运行状态:当进程被创建时,会进入到就绪队列,操作系统会从就绪队列选择一个进程运行;
- 运行状态 -> 结束状态:当进程正常运行完成或异常出错时,会被操作系统作结束状态处理,操作系统得从就绪队列选择另外一个进程运行;
- 运行状态 -> 阻塞状态:当进程请求某个事件且必须等待时,例如请求 I/O 事件,此时操作系统必须选择另外一个进程运行;
调度算法分类
- 抢占式调度算法(正在运行时可被打断)
- 从就绪队列中挑选一个进程,然后让该进程只运行一段时间,如果在该时间段结束时,该进程还没执行完,则会把它挂起,接着调度程序从就绪队列挑选另外一个进程。
- 抢占式调度处理,需要在时间间隔的末端发生时钟中断,以便把 CPU 控制返回给调度程序进行调度,也就是常说的时间片机制;
- 非抢占式调度算法:
- 从就绪队列中挑选一个进程,然后让该进程一直运行,直到该进程运行结束或被阻塞,才会调用另外一个进程,这种没有时钟中断。
常见调度算法有哪些
1️⃣ 先来先服务(FCFS)
最简单的调度算法,就是非抢占式的先来先服务(First Come First Severd, FCFS)算法了。
先来后到,每次从就绪队列选择最先进入队列的进程,然后一直运行,直到进程退出或被阻塞,才会继续从队列中选择第一个进程接着运行。
缺陷:
FCFS 对长作业/进程有利,适用于 CPU 繁忙型作业的系统,而不适用于 I/O 繁忙型作业的系统。
若进程是CPU繁忙型,则一旦占有CPU,就可能会运行很长时间,因此CPU繁忙型作业类似于长作业,FCFS算法对长作业/进程有利;
而对于I/O繁忙型进程作业,运行进程中要频繁访问I/O端口,即可能频繁放弃CPU,所以占用CPU的时间不会太长,一旦放弃CPU,则必须等待下次调度,因此FCFS算法不利于它。
看个例子(王道):
2️⃣ 最短作业优先(SJF)
最短作业优先(Shortest Job First, SJF),它会优先选择运行时间最短的进程来运行,这有助于提高系统的吞吐量。
SJF是非抢占式的算法。但也有个抢占式的版本:最短剩余时间优先(Shortest Remaining Time Next, SRTN)。
缺陷:
对长作业不利,很容易造成一种极端现象,如果源源不断地有短作业进程到来,可能会使得长作业进程长时间得不到服务,产生饥饿。
比如,一个 长作业/进程 在就绪队列等待运行,而这个就绪队列有非常多的短作业,那么就会使得长作业不断的往后推,周转时间变长,致使 长作业进程 长期不会被运行(长作业进程饥饿)。
看个例子(王道):
短作业优先
最短剩余时间优先
3️⃣ 高响应比优先(HRRN)
非抢占式的高响应比优先 (Highest Response Ratio Next, HRRN)算法主要是权衡了短作业和长作业。
每次进行进程调度时,先计算「响应比优先级」,然后运行「响应比优先级」最高的进程,响应比优先级计算公式如下:
\]
要求服务时间就是运行时间,一个任务的要求服务时间一般是固定的,而等待时间动态变化,等于从进入就绪队列到被CPU调度这段时间
公式分析:
等待时间相同时,要求服务时间越短,优先级越高,短作业进程容易被选中运行;
要求服务时间相同时,等待时间越长,优先级越高,兼顾了长作业进程,避免长作业进程饥饿的问题;
看个例子(王道):
4️⃣ 时间片轮询(RR)
使用最广的算法就是时间片轮转(Round Robin, RR)了。
每个进程被分配一个时间段,称为时间片(Quantum),即允许该进程在该时间段中运行,
- 如果时间片用完,进程还在运行,那么将会把此进程挂起,并把 CPU 分配另外一个进程(从就绪队列选);
- 如果该进程在时间片结束前阻塞或结束,则 CPU 立即切换到下一个进程;
缺陷:
1)如果时间片设置太短会导致频繁地发生进程上下文切换,降低了 CPU 效率;
2)如果设置太长,可能引起对短作业进程的响应时间变长,一般时间片设为 20ms~50ms
是一个比较合理的折中值。
5️⃣ 最高优先级调度(HPF)
每次 CPU 调度时都是从就绪队列中选择最高优先级的进程运行,称为最高优先级(Highest Priority First,HPF)调度算法。
该算法也有两种处理优先级高的方法:
- 抢占式:当就绪队列中出现优先级高的进程,当前进程挂起,调度优先级高的进程运行;
- 非抢占式:当就绪队列中出现优先级高的进程,运行完当前进程,再选择优先级高的进程;
缺陷:
可能会导致低优先级的进程永远不会运行。
6️⃣ 多级反馈队列(MFQ)
多级反馈队列(Multilevel Feedback Queue)调度算法是「时间片轮转算法」和「最高优先级算法」的综合和发展。
「多级」表示有多个就绪队列,每个队列优先级从高到低,同时优先级越高时间片越短;
「反馈」表示如果有新的进程加入优先级高的就绪队列时,立刻停止当前正在运行的进程,转而去运行优先级高的队列;
工作方式(⚠⚠⚠):
- 设置多个就绪队列,每个队列有着不同优先级,每个队列按优先级从高到低排列,同时优先级越高的队列设置的时间片越短;
- 每次新的进程会被放入到第一级队列(优先级最高)的末尾,按先来先服务的原则排队等待被调度,如果某个进程在第一级队列设置的时间片内没运行完,则将其转入到第二级队列的末尾,以此类推,直至完成;
- 当较高优先级的队列为空,才调度较低优先级的队列中的进程运行。如果进程运行时,有新进程进入较高优先级的队列(如就绪队列3),则停止当前运行的进程(如就绪队列5)并将其移入到原队列末尾,接着让较高优先级的进程运行;
优点:
1)对于短作业可以在第一级队列很快被处理完;
2)对于长作业,如果在第一级队列处理不完,可以移入下级队列等待被执行;
3)该算法很好的兼顾了长短作业,同时有较好的响应时间。
小结
参考
//xiaolincoding.com/os/#小白适合看吗
//blog.csdn.net/zh13487/article/details/83928284
//www.bilibili.com/video/BV1YE411D7nH