很多人第一次做实时系统时,都会有一种很强的疑惑:
• CPU 占用不高
• 程序跑得也不慢
• 平均响应时间看起来不错
• 系统大多数时候都正常
可一上现场,问题还是来了:
• 周期任务偶尔抖一下
• EtherCAT 主站偶发超周期
• 控制线程偶尔晚一点
• 系统看起来不忙,却总会“偶发异常”
这时候很多人就会问:
Linux 明明已经很快了,为什么还说它“不实时”?
答案其实很简单:
快,说的是平均表现;实时,说的是关键任务在最坏情况下也要尽量按时执行。
这就是两者最本质的区别。
1. 一句话先讲清楚
如果只记一句话,可以先记这个:
快看平均,实时看最坏情况。
普通系统更关心:
• 平均执行时间
• 吞吐量
• CPU 利用率
• 大多数时候的表现
而实时系统更关心:
• 最大延迟
• 抖动大小
• 是否错过截止时间
• 高优先级任务能不能稳定按时运行
所以一个系统就算大多数时候都很快,也不代表它就够“实时”。
2. 为什么“平均性能好”不代表“实时性好”?
因为这两个指标,关注的根本不是同一件事。
举个简单例子。
假设一个任务要求每 1ms 执行一次。
你测出来发现:
• 大多数时候延迟只有 50us
• 偶尔 80us
• 看起来非常漂亮
如果只看平均值,你会觉得这系统很好。
但如果某一次突然变成:
• 5ms
• 8ms
• 甚至更久
那对普通应用来说,也许只是“慢了一下”;
但对实时控制来说,这一次就可能足够致命。
因为实时系统最怕的,不是一直慢,而是:
• 偶发超时
• 偶发抖动
• 关键周期突然掉链子
所以实时系统真正怕的,不是平均值不够好,而是:
关键时刻突然慢很多。
3. Linux 为什么容易出现“平时快,偶尔慢”?
这和 Linux 的设计目标有关系。
普通 Linux 从来不是只为一个周期任务服务的。
它要同时处理很多事情:
• 多任务调度
• 中断处理
• 驱动工作
• 网络收发
• 文件系统
• 内存回收
• 各类内核线程
这意味着你的关键任务,即使平时跑得很好,也可能在某个时刻被这些事情打断。
最常见的干扰源包括:
• 中断处理过长
• 网络 softirq 突发
• 锁竞争
• 调度延迟
• 驱动路径不可抢占时间过长
• 某些线程优先级配置不合理
这些问题平时不一定明显,但一旦落在关键周期上,就会表现成:
• 线程抖动
• 控制超时
• 同步失稳
• 系统偶发异常
所以很多实时问题最麻烦的地方就在于:
它不是一直错,而是偶尔错。
也正因为如此,才更难查。
4. 实时系统真正该看什么?
做普通系统优化时,很多人喜欢看:
• 平均耗时
• 平均延迟
• CPU 使用率
• 吞吐量
但做实时系统时,关注点要换成:
• 最大延迟
• jitter 抖动
• deadline miss
• worst-case latency
也就是说,实时系统最关心的不是“平均多好”,而是:
最差的时候到底有多差。
因为现场很多问题,不是被平均值搞出来的,而是被那极少数峰值搞出来的。
所以实时优化本质上是在做一件事:
不是单纯让系统更快,而是让关键路径更稳。
5. PREEMPT_RT 为什么重要?
因为 PREEMPT_RT 干的事情,本质上就是:
尽量减少那些会让关键任务突然变慢的路径。
它不是简单提升跑分,而是在这些地方做改造:
• 提高内核可抢占性
• 缩短不可抢占区
• 中断线程化
• 改善锁机制
• 提高高优先级任务的调度机会
所以 PREEMPT_RT 的价值,不是让 Linux “平均更快”,而是:
让系统关键任务更可预测。
6. 最容易犯的 3 个误区
误区 1:CPU 占用不高,所以系统肯定没问题
不对。
实时问题很多时候不是 CPU 总量不够,而是关键时刻 CPU 被谁拿走了。
误区 2:平均延迟很好,说明系统实时性很好
也不对。
实时系统真正怕的是偶发长尾,不是平均值难看。
误区 3:打了 RT 补丁就一定没问题
还是不对。
驱动、中断、优先级、绑核、线程设计,都会影响最终结果。
7. 最后怎么一句话解释?
如果你想快速讲清这个问题,可以直接说:
Linux 跑得快,不代表它实时;因为实时系统关心的不是平均性能,而是关键任务在最坏情况下也要尽量按时执行。
如果再压缩成一句最容易记的话,就是:
普通系统看平均,实时系统看峰值。
结尾
很多人第一次做实时系统,都会先被“平均表现”迷惑。
系统平时很快、CPU 也不忙、程序也没报错,看起来一切正常。
但真正的问题,往往就出在那极少数“偶尔慢一下”的瞬间。
所以 Linux 明明跑得很快,却不一定是“实时”的,根因就在这里:
普通系统追求平均表现,实时系统追求关键任务稳定按时执行。
把这件事想明白,后面再去看:
• PREEMPT_RT 为什么重要
• 中断线程化为什么重要
• cyclictest 到底在测什么
思路就会清楚很多。