解决问题一的方式可以提炼出一个规则:
规则 5:经过一段时间S后,将所有工作都加入到最高优先级
这样的话,计算型的工作也可以以轮转的方式和其他工作共享CPU(因为他们在同一优先级)。同时,如果一个工作从计算密集型变成了交互型,当所有工作都加入到最高优先级时,这样的工作也可以获得CPU。
咱们再来解决问题二,这里的痛点是工作在时间片以内释放 CPU时,就保留它的优先级。那么解决办法就是让CPU为每个工作分配的时间比例尽量“公平”,也就是说,调度程序应该记录一个进程在某一层中消耗的总时间,而不是在调度时重新计时。只要进程用完了自己的配额,就将它降到低一优先级的队列中去。不论它是一次用完的,还是拆成很多次用完。那么我们可以总结一下这个规则:
规则 4:一旦工作用完了其在某一层中的时间配额(无论中间主动放弃了多少次CPU),就降低其优先级(移入低一级队列)
这样,不论进程的 I/O 行为如何,都会慢慢地降低优先级,因而无法获得超过公平的 CPU 时间比例。
3、MLFQ调优及其他问题
关于 MLFQ 调度算法还有一些问题。其中一个大问题是如何配置一个调度程序,例如,配置多少队列?每一层队列的时间片配置多大?为了避免饥饿问题以及进程行为改变,应该多久提升一次进程的优先级?这些问题都没有显而易见的答案,因此只有利用对工作负载的经验,以及后续对调度程序的调优,才会导致令人满意的平衡。
例如,大多数的 MLFQ 变体都支持不同队列可变的时间片长度。高优先级队列通常只有较短的时间片(比如 10ms 或者更少),因而这一层的交互工作可以更快地切换。