在上一篇文章中,我们讨论了实时网络。

当传感器、伺服驱动器、机器人关节以及其他工业设备通过 EtherCAT、TSN 等实时网络与控制器连接之后,实时系统面对的问题就不再只是“CPU什么时候运行任务”,而变成了一个完整的端到端问题:数据什么时候产生、什么时候到达、什么时候触发任务、任务什么时候获得 CPU、什么时候完成计算,以及控制指令什么时候再次通过网络发送出去。

但当我们继续往下研究实时 Linux,就会遇到另外一个非常有意思的问题:

CPU核心越多,实时性是不是就一定越好?

从普通计算的角度看,答案似乎很简单。

一颗 CPU 有 8 个核心,当然比 1 个核心拥有更多的计算资源;16 核似乎又应该比 8 核更强。对于视频处理、AI 推理、编译、大数据分析等高吞吐任务,多核确实可以显著提高并行计算能力。

但是,实时系统关心的并不是单纯的“单位时间完成多少工作”,而是:

一个关键任务能不能在规定的时间内稳定完成。

这两个目标并不完全相同。

在普通计算系统中,我们往往希望 CPU 尽可能“忙起来”,让所有核心都参与工作;而在硬实时系统中,有时候恰恰需要故意让某些核心“少干一点活”,甚至让一个 CPU 核心主要服务于某一类实时任务。

看起来这似乎浪费了 CPU。

实际上,它是在用一部分计算资源换取更强的时间确定性。

这也是理解多核实时 Linux 和核心隔离非常重要的一步。


一、多核CPU解决了“算力问题”,却带来了新的“确定性问题”

假设现在有一台 8 核工业控制器。

它同时运行:

  • 机器人运动控制;

  • 视觉算法;

  • AI 推理;

  • 工业网络;

  • 数据采集;

  • 日志服务;

  • Web 管理界面;

  • 数据库存储。

如果按照普通 Linux 的思路,很自然会希望操作系统自动把这些任务分配到 8 个 CPU 上。

理想状态可能是:

CPU0    CPU1    CPU2    CPU3
控制    视觉    AI      网络

CPU4    CPU5    CPU6    CPU7
日志    存储    UI      其他

看起来非常合理。

但实时系统真正担心的问题是:

这些任务真的会一直待在这里吗?

答案通常没有这么简单。

Linux 是一个通用操作系统,需要根据系统负载、任务状态、CPU 利用率等因素动态进行调度。

一个任务可能在 CPU0 上运行了一段时间,然后因为各种原因迁移到 CPU1。

从普通应用的角度来看,这通常是正常的。

但是对于实时任务而言,任务迁移本身就可能产生额外成本。

例如:

CPU0
 └── 实时控制任务
        ↓
      迁移
        ↓
CPU1
 └── 继续执行

任务看起来只是从一个 CPU 移到了另一个 CPU。

实际上背后可能发生一系列变化:

  • CPU cache 状态发生变化;

  • 调度队列发生变化;

  • CPU 间通信增加;

  • 可能产生 IPI;

  • 原 CPU 和目标 CPU 的运行状态发生变化;

  • 共享数据可能产生额外同步;

  • 内存访问局部性可能改变。

这些因素单独看都不一定很严重。

但是实时系统最怕的恰恰就是:

大量小的不确定因素叠加起来,最终形成一次明显的延迟尖峰。

所以实时 Linux 中经常会出现一个看起来和“高性能计算”相反的思路:

不是让所有 CPU 都尽可能参与所有任务,而是让不同 CPU 承担明确的职责。

例如:

CPU0    CPU1    CPU2    CPU3
系统    系统    实时    实时
任务    任务    控制    控制

CPU4    CPU5    CPU6    CPU7
AI      AI      视觉    网络

其中 CPU2、CPU3 可以进一步进行核心隔离,主要服务于实时控制任务。

这样做的目的不是让 CPU2、CPU3 的计算能力更强。

而是:

减少谁都可以来使用这两个核心的情况。

这就是实时系统与普通高吞吐系统非常重要的区别。

普通系统更关心:

怎么把所有 CPU 都利用起来?

实时系统还需要考虑:

哪些 CPU 应该尽可能少被打扰?


二、任务迁移为什么会影响实时性?Cache是一个容易被忽略的因素

要理解多核实时性,必须先理解一个基础概念:CPU Cache。

现代处理器并不是每次执行指令都直接访问内存。

CPU 通常会通过多级 Cache 保存近期使用的数据和指令。

可以简单理解成:

CPU核心
  ↓
L1 Cache
  ↓
L2 Cache
  ↓
L3 Cache
  ↓
内存

越靠近 CPU,访问速度通常越快。

因此,一个任务如果长期在同一个 CPU 核心上运行,它使用过的数据和指令可能已经进入对应的 Cache。

下一次继续运行时,就可能直接从 Cache 中获得数据。

但如果任务从 CPU0 迁移到了 CPU1:

原来:

CPU0
 ├── L1
 ├── L2
 └── 实时任务

迁移后:

CPU1
 ├── L1
 ├── L2
 └── 实时任务

CPU1 并不一定拥有 CPU0 中完全相同的 Cache 工作集。

于是就可能出现 Cache miss。

简单来说:

任务虽然已经获得了 CPU,但它未必能够像刚才一样高效地继续运行。

对于普通程序来说,这可能只是性能下降。

对于实时程序来说,更值得关注的是:

这个额外开销是否具有稳定的上界?

实时系统并不一定害怕“慢”。

实时系统真正害怕的是:

不知道什么时候会突然慢下来。

例如,一个控制任务正常情况下执行时间可能只有 80 μs。

如果某次任务迁移、Cache miss、共享资源访问等因素叠加,使它变成了 130 μs,单次来看可能并不严重。

但如果这种变化没有明确的边界,工程人员在设计 1 ms 控制周期时,就很难给出稳定的最坏情况预算。

于是问题就变成:

平均执行时间:80 μs
通常执行时间:80~100 μs
偶发执行时间:?
最坏执行时间:?

实时系统最需要知道的是最后两个问题。

这也是为什么在实时 Linux 优化中,经常会强调:

不要只测试平均延迟,要观察 worst-case latency。

前面的 cyclictest 文章讨论的其实就是同一个逻辑。

平均值告诉你系统“通常怎么样”。

最大延迟则帮助你判断系统“最坏的时候怎么样”。


三、多核并不是“每个核心独立运行”:共享资源才是新的问题

如果多核 CPU 真的是完全独立的,那么实时系统设计会简单很多。

但现实中的多核处理器并不是这样。

多个 CPU 核心通常需要共享大量硬件资源:

        CPU0
          │
        Cache
          │
          ├─────────┐
          │         │
        CPU1       CPU2
          │         │
          └────┬────┘
               │
             L3 Cache
               │
            内存控制器
               │
              DRAM

不同核心可能共享:

  • LLC / L3 Cache;

  • 内存控制器;

  • 内存带宽;

  • PCIe;

  • DMA;

  • 网卡;

  • 存储设备;

  • 外设总线。

这意味着:

即使一个实时任务已经独占了 CPU 核心,也不代表它已经完全脱离其他任务的影响。

假设 CPU2 专门运行机器人控制任务。

CPU6、CPU7 正在运行 AI 推理。

AI 推理可能产生非常大的内存访问压力。

于是:

CPU2
实时控制
   │
   │
   ▼
共享内存系统
   ▲
   │
CPU6 / CPU7
AI推理

实时任务虽然没有和 AI 任务共享 CPU 核心,但它们可能共享内存带宽。

于是就可能出现:

CPU没有被抢走,但内存访问变慢了。

这就是现代实时系统越来越需要关注的一个问题:

资源隔离不能只看 CPU。

从更完整的角度看,实时资源隔离至少可以分成几个层次:

任务层
 ↓
CPU核心层
 ↓
IRQ层
 ↓
Cache层
 ↓
内存带宽层
 ↓
I/O层
 ↓
网络层

不同系统对这些资源的敏感程度不同。

对于控制周期比较宽松的系统,CPU核心隔离可能已经能够获得非常明显的效果。

而对于高速运动控制、飞控、实时仿真等对延迟更加敏感的场景,就可能需要进一步考虑 Cache、内存访问和 I/O 资源竞争。

这也解释了一个非常容易出现的误区:

核心隔离不是万能的。

它是建立实时执行域的重要基础,但并不意味着隔离之后系统中的所有不确定性都会自动消失。


四、为什么实时Linux经常强调“绑核”?CPU Affinity到底解决了什么

在 Linux 中,CPU affinity 可以让任务运行在指定 CPU 集合上。

例如:

控制任务
    ↓
CPU2
CPU3

而不是:

CPU0~CPU7

从调度角度看,这意味着实时任务可以被限制在一个相对确定的 CPU 范围内。

例如:

普通任务:

CPU0 ─┐
CPU1 ─┤
CPU2 ─┤
CPU3 ─┤
CPU4 ─┤→ Linux调度
CPU5 ─┤
CPU6 ─┤
CPU7 ─┘

而实时任务可以进一步变成:

实时任务
   │
   └── CPU2 / CPU3

这样做至少有三个好处。

第一,可以减少任务在多个 CPU 之间迁移。

第二,可以让实时任务拥有相对稳定的 CPU 执行环境。

第三,可以进一步配合 IRQ affinity、CPU isolation 等机制,把实时核心和普通业务核心划分开。

但这里需要特别强调:

CPU affinity 和 CPU isolation 不是一回事。

CPU affinity 更像是在告诉某个任务:

你只能去这些 CPU 上运行。

CPU isolation 则是在系统层面进一步减少:

其他任务、调度活动以及系统干扰进入这些 CPU。

两者结合起来,效果才更加完整。

例如:

             8核CPU
                │
       ┌────────┴────────┐
       │                 │
   非实时域           实时域
 CPU0/1/4/5/6/7      CPU2/3
       │                 │
 AI/视觉/日志        控制任务
 UI/存储             RT线程
 普通网络            实时网络
       │                 │
       └────────┬────────┘
                │
             系统级协同

这时候,CPU2、CPU3 并不是简单的“两个空闲核心”。

它们实际上已经成为系统中的一个实时执行域。

这个概念非常重要。

因为现代工业设备越来越倾向于把大量业务放在同一个计算平台上。

过去可能需要:

控制器 → 专门做控制
工业PC → 专门做计算
服务器 → 专门做AI

现在则越来越希望:

             一台高性能控制器
                    │
       ┌────────────┼────────────┐
       │            │            │
     实时控制      AI推理       视觉
       │            │            │
     EtherCAT      GPU/CPU      Camera

这样可以降低硬件复杂度,提高系统集成度。

但它同时提出了一个新的要求:

如何让不同性质的工作负载互不干扰?

这正是核心隔离价值越来越突出的原因。


五、从“多核计算”走向“多域计算”:实时Linux真正需要解决的问题

到这里,我们可以把前面整个实时 Linux 系列串起来。

最开始,我们讨论实时调度。

SCHED_FIFO、SCHED_RR、SCHED_DEADLINE 解决的是:

任务如何获得 CPU。

接着,我们讨论优先级反转。

它解决的是:

高优先级任务为什么有时候仍然会被低优先级任务阻塞。

然后我们讨论内存。

它解决的是:

任务执行过程中,为什么缺页、动态内存等机制可能造成不可预测延迟。

之后讨论 IRQ、SoftIRQ。

它解决的是:

系统中的异步事件为什么可能突然打断实时任务。

再之后,我们讨论 EtherCAT、TSN 等实时网络。

它解决的是:

数据能不能按照确定的时间关系到达控制器和执行器。

而今天讨论多核 CPU,实际上又回到了一个更底层的问题:

在拥有越来越多计算资源的情况下,如何保证实时任务的执行环境仍然具有确定性?

这几个问题最终可以形成一条完整的实时系统链:

                  实时Linux
                     │
     ┌───────────────┼────────────────┐
     │               │                │
   调度确定性      执行确定性       通信确定性
     │               │                │
 SCHED_FIFO       核心隔离          EtherCAT
 SCHED_RR         CPU Affinity      TSN
 SCHED_DEADLINE   IRQ隔离           PTP
     │               │                │
     └───────────────┼────────────────┘
                     │
              资源与时间隔离
                     │
              端到端实时控制

这时候再回头看“CPU核心越多是不是越实时”这个问题,就会发现答案并不是简单的“是”。

更多 CPU 核心意味着更多计算资源。

但更多核心也意味着:

  • 更多任务可能并行运行;

  • 更多任务可能发生迁移;

  • 更多 CPU 之间需要协调;

  • 更多共享 Cache 和内存资源需要竞争;

  • 更多 IRQ 需要分配;

  • 更多网络队列需要管理;

  • 更复杂的 NUMA 和内存拓扑可能出现;

  • 系统调度行为也更加复杂。

因此:

高性能多核 CPU 解决的是“能算多少”,而实时操作系统还必须解决“什么时候算完”。

这两个问题需要同时解决。

对于机器人来说,AI 可以负责视觉识别和路径规划,但关节控制仍然可能要求严格的周期执行。

对于智能制造来说,机器视觉可能需要大量计算,但 PLC 控制周期仍然需要稳定。

对于飞控来说,导航、感知和数据融合可能越来越复杂,但关键控制环路依然需要明确的时间约束。

对于实时仿真来说,CPU 可以拥有几十甚至上百个核心,但仿真步长仍然必须稳定推进。

这意味着未来的实时操作系统并不是简单地追求:

“把所有 CPU 都跑满。”

而是:

“把不同性质的任务放到合适的资源域,让实时任务拥有稳定的时间预算。”

这就是所谓的多域计算。

例如:

                多核智能控制平台
                       │
        ┌──────────────┼──────────────┐
        │              │              │
      实时域          AI域           系统域
        │              │              │
    CPU2/3          CPU4/5          CPU0/1/6/7
    核心隔离        AI推理          UI/日志/存储
    IRQ隔离         视觉            普通网络
    RT调度          数据处理        系统服务
        │              │              │
        └──────────────┼──────────────┘
                       │
                 统一硬件平台

这种设计思路非常适合未来机器人和智能制造设备。

因为真正的工业计算平台,很难再是一台“只运行控制程序”的机器。

它既需要实时控制,也需要 AI;既需要工业通信,也需要视觉;既需要高性能计算,也需要设备管理。

因此,实时操作系统的关键能力也会从过去的“让某一个任务实时”,逐渐发展成:

让一整套复杂计算系统中的关键任务保持实时。

而这正是核心隔离真正值得讨论的地方。

核心隔离并不是简单地把几个 CPU 核心划出来。

更完整的理解应该是:

通过 CPU 核心、任务、IRQ、内存、网络以及 I/O 等多层资源的合理划分,为实时任务建立一个低干扰、可预测的执行环境。

在这一架构下,望获OS所强调的核心隔离,也可以被放在一个更加完整的技术体系中理解。

它并不是孤立的一个功能点,而是与实时调度、IRQ隔离、资源管理、工业网络等能力共同组成实时系统的基础。

最终目标不是让系统中每一个任务都变成实时任务。

恰恰相反。

真正合理的设计,是:

让需要实时的任务实时,让需要高吞吐的任务获得高吞吐,让不同任务运行在适合自己的资源域中。

这样才能让 AI、机器人、工业控制和智能制造真正走向融合。


结语:实时系统不是追求“更多CPU”,而是追求“更确定的CPU”

从单核到多核,从 2 核到 8 核、16 核甚至更多核心,计算平台的性能已经发生了巨大变化。

但实时系统面对的问题并没有因此消失。

恰恰相反:

算力越强,系统往往越复杂;系统越复杂,实时确定性越难保证。

一个拥有几十个 CPU 核心的控制器,如果所有任务、中断、网络和 AI 计算都混在一起运行,它未必比一个经过合理隔离的多核实时系统更加稳定。

因为实时系统真正关心的不是:

“我有多少个核心?”

而是:

“我的关键任务能不能在规定的时间窗口内稳定获得资源并完成执行?”

因此,多核实时 Linux 的核心思路并不是简单地追求 CPU 利用率最大化,而是在性能和确定性之间建立合理的资源边界。

从 CPU affinity 到核心隔离,从 IRQ affinity 到实时调度,再到内存和网络资源隔离,本质上都是在做同一件事:

降低实时任务面对的不确定性。

这也是实时 Linux 从“实时调度”走向“实时系统”的重要一步。

下一阶段,当 AI、机器人、工业控制和边缘计算进一步融合之后,真正值得研究的问题也许已经不是:

“Linux能不能实时?”

而是:

“一台多核、高算力、网络化的智能控制平台,能不能同时做到高性能和强确定性?”

这才是实时操作系统在智能制造、机器人、实时仿真以及复杂嵌入式系统中需要持续回答的问题。

而答案,显然不会只存在于调度器里。

它会存在于CPU、核心隔离、内存、中断、网络、I/O以及整个系统架构之中。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐