进程调度是操作系统中相当重要的一部分,Linux是多任务的操作系统,进程无法始终占有CPU运行;对于单处理器系统来说,事实上多个进程仅仅是轮流在自己的时间片使用CPU资源;只有在多处理器系统中,多个进程才有可能真正的做到同时、并行的执行。
多任务系统也分为非抢占式多任务和抢占式多任务系统;在非抢占式多任务的系统中,下一个任务被调度的前提是当前进程主动让出CPU的使用权,因此非抢占式多任务又称为合作型多任务。而抢占式多任务由操作系统来决定进程调度,在某些时间点上,操作系统可以将正在运行的进程调度出去,选择其他进程来执行。毫无疑问,Linux属于抢占式多任务系统。事实上,大多数的现代操作系统都是抢占式的多任务系统。
不同的进程之间,其行为模式可能存在着巨大的差异。进程的行为模式可以粗略地分成两类:CPU消耗型(CPU bound)和I/O消耗型(I/O bound)。
每个进程运行多长时间,是任何一个调度算法都不能回避的问题。传统的调度算法面临着一种困境,那就是时间片到底多大才合适?如果时间片太大,进程执行前需要等待的时间就会变长,当CPU运行队列上可运行进程的个数比较多的时候尤为明显,用户可能会感觉到明显的延迟。如果时间片太短,进程调度的频率就会增加,考虑到上下文切换也需要花费时间,可以想见,大量的时间都浪费到了进程调度上。
完全公平调度,使用了一种动态时间片的算法。它给每个进程分配了使用CPU的时间比例。进程调度设计上,有一个很重要的指标是调度延迟,即保证每一个可运行的进程都至少运行一次的时间间隔。比如调度延迟是20毫秒,如果运行队列上只有2个同等优先级的进程,那么可以允许每个进程执行10毫秒,如果运行队列上是4个同等优先级的进程,那么,每个进程可以运行5毫秒。考虑到有些任务优先级比较高,需要更多的运行时间,完全公平调度通过引入调度权重来实现优先级,进程之间按照权重的比例,分配CPU时间。
分配给进程的运行时间=调度周期*进程权重/运行队列所有进程权重之和
调度周期(Scheduling Period):这是 CFS 使用的一个参考时间周期。调度周期定义了在该周期内,所有可运行进程将轮流获得 CPU 使用权。调度周期的长度根据系统的负载(即运行队列中的进程数量)动态调整。
进程权重(Process Weight):CFS 使用一个与 nice 值相关的权重系统来分配 CPU 时间。nice 值的范围从 -20 到 19,其中 -20 对应的权重最大,优先级最高。系统会为每个进程根据其 nice 值计算权重,nice 值越低,权重越大,分配的 CPU 时间片就越长。
运行队列所有进程的权重之和:这是系统中所有正在等待 CPU 的进程权重之和。进程的权重相对整个队列的权重总和,决定了它所能获得的 CPU 时间片。
Linux下每一个进程都有一个nice值,该值的取值范围是[-20,19],其中nice值越高,表示优先级越低。默认的优先级是0。下面命令就可以查看到进程的优先级,NI列中描述了当前进程的优先级信息。
| ps -eo pid,user,pri,ni,cmd |
205