第四节:调度策略基础——FPS、EDF、RR
调度策略,说白了就是决定“下一个该谁跑”。
在多核处理器上,这个决策会直接影响你的实时性、抖动、甚至系统会不会崩。我见过不少工程师,上来就写任务,跑起来没问题,一上负载就翻车。为什么?调度策略没选对。
今天咱们把三种最基础的调度策略讲透:固定优先级调度(FPS)、最早截止时间优先(EDF)、轮转调度(RR)。这三种策略,你搞懂了,后面优化才有根基。
一、固定优先级调度(FPS)
FPS 是最直观的策略。每个任务分配一个固定的优先级,高优先级任务永远先执行。
我个人习惯用 FPS 做第一版原型。为什么?简单、可预测、开销小。
核心规则
- 优先级在任务创建时设定,运行期间不变
- 高优先级任务就绪时,立即抢占低优先级任务
- 同优先级任务按时间片轮转(或 FIFO)
我在项目中遇到过的问题
有一次做汽车电控单元,一个传感器采集任务优先级设得太高,结果把控制算法任务饿死了。车子在台架上跑得好好的,一上路就抖。查了两天才发现是优先级反转——低优先级任务持有了高优先级任务需要的资源。
适用场景
- 任务周期固定、可预测
- 任务数量不多(< 15 个)
- 对抖动要求不高
二、最早截止时间优先(EDF)
EDF 是动态优先级策略。谁的时间最紧迫,谁先跑。
你想想看,FPS 是“官大一级压死人”,EDF 是“谁先死谁先跑”。
核心规则
- 每个任务有一个截止时间(deadline)
- 调度器选择当前截止时间最早的任务执行
- 截止时间越近,优先级越高(动态变化)
EDF 的优势
理论上,EDF 的 CPU 利用率可以达到 100%。FPS 在 RMS 下最高只有约 69%(n→∞时)。这意味着同样的硬件,EDF 能跑更多任务。
我记得在 dSPACE 的 SCALEXIO 平台上做过一个对比实验:同样 10 个任务,FPS 在 70% 负载时就开始丢 deadline,EDF 撑到了 95%。
EDF with overload handling,或者加一个监控任务做看门狗。
适用场景
- 任务周期不固定、突发性强
- CPU 利用率要求高
- 有足够的计算资源做动态调度
三、轮转调度(RR)
RR 是最公平的策略。每个任务轮流执行一个时间片,时间到了就换人。
说白了,就是“一人一筷子,吃完换下家”。
核心规则
- 所有任务优先级相同
- 每个任务分配固定时间片(如 1ms、10ms)
- 时间片用完,任务被挂起,下一个任务执行
我在项目中踩过的坑
有一次做数据采集系统,用了 RR 调度。结果发现某个任务每次执行到一半就被切走,数据写到一半就丢了。查了半天,原来是时间片设得太短(0.5ms),任务连一个完整的数据帧都发不完。
- 计算密集型任务:时间片设长一点(10-50ms),减少上下文切换开销
- I/O 密集型任务:时间片设短一点(1-5ms),提高响应速度
- 混合型:按最坏情况执行时间(WCET)的 2-3 倍来设
适用场景
- 所有任务重要性相同
- 对公平性要求高
- 任务执行时间差异不大
三种策略对比
| 特性 | FPS | EDF | RR |
|---|---|---|---|
| 优先级 | 固定 | 动态 | 相同 |
| CPU 利用率上限 | ~69%(RMS) | 100% | 取决于时间片 |
| 实现复杂度 | 低 | 中 | 低 |
| 抖动 | 中 | 低 | 高 |
| 多米诺效应风险 | 低 | 高 | 低 |
| dSPACE 推荐场景 | 快速原型、控制算法 | 高负载、多任务 | 数据采集、日志 |
dSPACE 中的配置示例
在 dSPACE 的 ConfigurationDesk 中,你可以这样设置调度策略:
// FPS 配置示例
TaskConfig task1;
task1.priority = 10; // 高优先级
task1.scheduling = FPS;
task1.period = 1.0; // 1ms 周期
TaskConfig task2;
task2.priority = 5; // 低优先级
task2.scheduling = FPS;
task2.period = 10.0; // 10ms 周期
// EDF 配置示例
TaskConfig task3;
task3.deadline = 2.0; // 截止时间 2ms
task3.scheduling = EDF;
task3.period = 5.0;
// RR 配置示例
TaskConfig task4;
task4.timeSlice = 5.0; // 5ms 时间片
task4.scheduling = RR;
task4.priority = 0; // RR 下优先级无效
- 核 0:运行 FPS 任务(控制算法、安全关键任务)
- 核 1:运行 EDF 任务(数据融合、复杂计算)
- 核 2:运行 RR 任务(日志、监控、非实时任务)
这样既能保证实时性,又能充分利用 CPU。
小结
三种策略没有绝对的好坏。FPS 稳,EDF 狠,RR 公平。选哪个,取决于你的任务特性和硬件资源。
我个人建议:先 FPS 起步,遇到瓶颈再切 EDF,非实时任务丢给 RR。别一上来就搞复杂调度,容易翻车。
下一节咱们聊聊多核环境下的任务绑定和缓存亲和性优化。嗯,那个才是真正拉开差距的地方。