4、经典调度算法(上):先来先服务(FCFS)、短作业优先(SJF)、时间片轮转(RR),优缺点分析。

调度算法这东西,说白了就是操作系统怎么决定「下一个该谁上CPU跑」。我刚开始做调度系统时,觉得这玩意儿不就是排个队嘛,有啥难的?结果真上手了才发现,排队的姿势不同,系统性能天差地别。

今天咱们先聊三个最经典的调度算法:先来先服务(FCFS)、短作业优先(SJF)、时间片轮转(RR)。这三个是调度领域的「三原色」,后面的复杂算法基本都是在它们基础上组合、优化出来的。

核心观点:没有完美的调度算法,只有适合场景的调度策略。你选哪个,取决于你的系统是「要吞吐量」还是「要响应快」。

经典调度算法知识体系 FCFS 先来先服务 公平但效率低 SJF 短作业优先 高效但易饿死 RR 时间片轮转 响应快但开销大 评价维度对比 公平性:FCFS > RR > SJF 吞吐量:SJF > FCFS > RR 响应时间:RR > FCFS > SJF 实现复杂度:FCFS < RR < SJF

4.1 先来先服务(FCFS)—— 最朴素的排队

FCFS 的逻辑简单到令人发指:谁先到,谁先跑。就像你去银行办业务,取号排队,先来的先办。

我早期做的一个嵌入式项目,用的就是 FCFS。当时觉得「这算法也太没技术含量了吧」,结果跑了一段时间发现——嗯,真香。代码量少,逻辑清晰,调试起来毫无压力。

但问题也很明显。你想想看,如果前面排了一个大任务,跑 10 秒才结束,后面一堆只需要 1 毫秒的小任务就只能干等着。这就是所谓的「护航效应」——大任务像一艘航母,后面跟着一堆小快艇,全被堵死了。

FCFS 优缺点总结:

  • 优点:实现简单,公平(按到达顺序),适合长作业、CPU 密集型场景
  • 缺点:平均等待时间长,不适合交互式系统,护航效应严重

避坑指南:我曾经在一个实时性要求不高的日志处理系统中用了 FCFS,结果因为一个超大日志文件导致后续所有小任务延迟了十几秒。后来我加了个超时打断机制才解决。所以记住——FCFS 只适合你对响应时间没要求、任务大小相对均匀的场景。

4.2 短作业优先(SJF)—— 谁短谁先跑

SJF 的思路很直接:预估每个任务的执行时间,谁短谁先上。这听起来很合理对吧?毕竟短任务跑得快,先处理完它们,系统整体吞吐量就上去了。

我有个朋友做大数据批处理,他们系统用的就是 SJF 的变种。效果确实好,吞吐量比 FCFS 提升了 30% 以上。但问题来了——长任务怎么办?

如果系统一直有短任务进来,长任务就永远排不上队。这就是「饥饿现象」。长任务就像在食堂排队,前面不断有人插队(短任务),它永远吃不上饭。

而且 SJF 有个致命弱点:你咋知道任务要跑多久? 实际系统中,任务执行时间很难精确预估。我见过有人用历史平均值来估算,但碰上突发情况就全乱套了。

SJF 优缺点总结:

  • 优点:平均等待时间最短,吞吐量最高,适合批处理系统
  • 缺点:长任务可能饿死,需要预估执行时间(现实中很难),不适合交互式系统

注意:SJF 有抢占式版本(SRTF,最短剩余时间优先),效果更好但实现更复杂。我曾经在一个实时调度项目中尝试过 SRTF,结果因为频繁的上下文切换,CPU 开销反而上去了。所以别盲目追求「最优」,要结合硬件成本来权衡。

4.3 时间片轮转(RR)—— 每人分一口

RR 的思路是:每个任务轮流跑一小段时间(时间片),跑完就换下一个。这样谁都不会等太久,响应时间很均匀。

你想想看,如果时间片设成 10 毫秒,那每个任务最多等 (n-1)*10 毫秒就能轮到一次。这对交互式系统来说太友好了——用户敲个键盘,系统很快就能响应。

但 RR 有个核心问题:时间片设多大?

设小了,上下文切换太频繁,CPU 全花在「换人」上了。我记得有个项目,时间片设成 1 毫秒,结果上下文切换开销占了 CPU 的 40%,业务逻辑反而跑不动了。

设大了呢?比如设成 100 毫秒,那跟 FCFS 就没啥区别了——一个任务跑完 100 毫秒才让出 CPU,其他任务照样等得心焦。

RR 优缺点总结:

  • 优点:响应时间均匀,适合交互式系统,公平性好
  • 缺点:上下文切换开销大,吞吐量相对较低,时间片选择困难

我的经验:时间片一般设为 10-50 毫秒比较合适。我习惯的做法是:先根据 CPU 频率和任务数量估算一个基准值,然后通过压测调整。如果上下文切换开销超过 10%,就适当增大时间片。说白了,这是个「调参」的活,没有标准答案。

4.4 三种算法对比一览

维度 FCFS SJF RR
核心思想 先来先跑 短任务优先 轮流跑
平均等待时间 较长 最短 中等
响应时间 差(长任务拖累) 差(长任务饿死) 好(均匀)
吞吐量 中等 高 较低
公平性 好(按到达顺序) 差(长任务吃亏) 好(轮流)
实现复杂度 极低 中等(需预估时间) 低
适用场景 批处理、非交互 批处理、任务时间已知 交互式、分时系统

看到这个表格,你应该能感受到——没有银弹。每个算法都有自己的「舒适区」和「死穴」。我个人的习惯是:先搞清楚你的系统是「要吞吐量」还是「要响应快」,然后再选算法。如果两者都要,那就得用更复杂的多级队列调度了——这个咱们后面章节再聊。

嗯,今天就先到这儿。这三种算法是调度领域的基石,理解透了,后面学多级反馈队列、公平调度什么的就轻松多了。

想要更多资料,联系可可