综述
内核调度子系统负责进程调度,调度程序决定让哪个进程运行、什么时候运行、运行多久。调度程序的目标有两个:一个是最大化系统资源的利用率,一个是减少和用户的交互延迟,让用户觉得多个进程在同时运行。这两个目标是冲突的,需要做trade-off。
多任务操作系统
多任务操作系统指的是指可以多个进程同时交错执行的操作系统。在单处理器机器上,用户会产生有多个进程同时在不同的处理器上在同时执行的错觉。多任务系统可以分成两种:协作式(cooperative)和抢占式(preemptive)多任务系统。包括Linux、Windows在内的大部分操作系统都属于抢占式多任务系统。
抢占式多任务操作系统中,调度程序决定一个进程什么时候停止执行。调度程序终止一个进程的执行(并不是这个进程自愿的)并让另一个进程执行的行为被称为抢占,进程在被抢占之前可以运行的时间一般由调度程序预先确定,被称为时间片(timeslice)。时间片一般是动态计算的,Linux没有直接使用时间片,而是使用了处理器比例(processor proportion)来规定进程运行时间。
协作式多任务操作系统中,调度程序无法决定进程可以运行多久,一个进程除非自己主动地暂停并放弃CPU,否则可以一直执行下去,独占CPU,不会出现抢占的情况。进程通常会主动暂停执行,否则系统可能就会宕机了。
I/O-Bound进程和Processor-Bound进程
进程可以分为I/O-Bound和Processor-Bound,前者代表进程花费大量时间提交和等待I/O请求,这种类型的进程通常执行一段很短的时间,然后阻塞等待新的I/O,大部分GUI应用属于I/O bound,虽然GUI应用很少读写磁盘,但是他们花费大量时间等待用户通过键盘和鼠标进行交互。Processor-Bound进程是花费大量时间执行代码的进程,通常只有被抢占的时候才会停止执行,因为他们不会因为I/O请求被阻塞。对于Processor-Bound进程,调度策略倾向于让进程以较少的运行次数执行较长的时间,即每次运行时间较长。
这两种类别并不是互斥的,进程可以同时具有这两类行为,X Windows Server既是I/O-Bound也是Processor-Bound。文字处理软件大部分时间在等待用户输入(I/O-Bound),但是某些时刻会进行拼写检查或者宏计算等(Processor-Bound)。
调度程序必须尝试同时满足两个互相冲突的目标:快速响应(低延时)和最大化系统利用率(高吞吐量)。为了选择“最有价值的”的进程执行并同时照顾其他低优先级的进程,调度器通常需要采用非常复杂的调度策略。Unix系统的调度策略通常优先考虑低延时目标,Linux为了确保优秀的交互响应和桌面系统性能也优先考虑低延时目标,但是Linux采用的调度策略并不会忽视Processor-Bound进程(稍后会说)。
进程优先级
基于优先级的调度算法是一种典型的调度算法,根据进程的价值和需求给进程一个合适的优先级,通常(Linux中不是这样做的),优先级高的进程先于优先级低的进程运行,优先级相同的进程使用循环(round-roubin)方式运行。此外,优先级高的进程还会获得更长的时间片。
Linux内核中进程可以分为互斥的两种:普通进程(normal process) 和 实时进程(read-time process)。后者的优先级永远高于前者,两者分别使用独立的优先级范围,只有当没有实时进程需要运行时,普通进程才能够获得调度。前者使用nice值,是一个-20到19之间的数值,nice值越大,优先级越低(对其他进程来说你很nice),nice值越小优先级越大(这个进程对其他进程来说不nice)。不同的Unix系统对nice值的处理是不一样的,Mac OS X中使用nice值确定时间片的绝对长度,Linux中,nice值控制时间片的分配比例(timeslice proportion),nice值越小,获得的比例越大(这里的比例可以理解度时间片的相对长度)。Linux中使用ps -el命令可以查看进程的nice值(NI列),值为“-”的进程是read-time process,没有nice值。
read-time proc