2026年8月29日 · benchmarks · honesty · performance · ros2
我们撤回了那个 ROS 2 加速数字。这是我们能守住的那一个。
HORUS 曾经宣称比 ROS 2 快几十倍——那个数字是编造的。这里是我们撤回了什么、为什么撤回、以及那个你能在自己机器上复现的、真正被测量过的数字。
我们曾经把一个数字挂在 README 上:HORUS 比 ROS 2 快几十倍。
那个数字是错的。它不是测量出来的——它是编造的。
这篇文章讲三件事:我们撤回了什么、为什么撤回、以及那个你能在自己机器上跑出来的、真正被测量过的数字。
那个被撤回的数字,到底是怎么造出来的?
事情很简单,简单到难堪:我们把一个 HORUS 自己测出来的真实数字,除以一个没人跑出来过的 ROS 2 延迟。那个 ROS 2 的"几十微秒"在 HORUS 仓库里没有任何 benchmark、没有任何报告、没有任何来源——它是编出来的。然后我们用真实的 HORUS 数字除以它,得到了一个看起来很漂亮的倍数。
这个倍数流到了 README、文档、社交媒体卡片,甚至一整篇博客文章里,直到有人认真去查。
我们撤回了它。
我们能守住的 ROS 2 比较,只有一个
HORUS 仓库里真正存在的 ROS 2 数字只有一个:REP 2014 中引用的、64 字节消息约 5 µs 的参考值。这个数字来自文献,不是我们自己测的。
HORUS 自己测出来的端到端跨进程延迟是 171 ns(单向,RDTSC 时间戳嵌入 payload,CPU 绑核,5000 次预热迭代后采样)。用 5 µs 除以 171 ns,大约是 30×。
30× 是我们能守住的上限。这也是我们唯一会用的数字。
# 在你自己的机器上复现 171 ns 这个数字
cargo run --release -p horus_benchmarks --bin all_paths_latency注意:这个 171 ns 是端到端、单向的。它和我们另外一些数字不是同一类——比如同进程发布/订阅的 91 ns,那是生产者侧的 send() 开销,没有消费者在路径上。把 send() 开销和端到端延迟放在一起比较,是在拿苹果比橙子。
真正值得拿来比较的,是 iceoryx2
如果我们想让你看到一个两边都测过的比较,我们不会拿 ROS 2——我们会拿 iceoryx2。
原因很简单:ROS 2 那一侧我们没跑过,iceoryx2 这一侧我们跑了。同一个测试框架,同一台机器,同样的 RDTSC + bootstrap 95% CI 方法论。
| 场景 | HORUS | iceoryx2 | 倍数 |
|---|---|---|---|
| 同线程 | 11 ns | 69 ns | 6.3× |
| 跨进程 | 170 ns | 361 ns | 2.1× |
| 吞吐 | 95M msg/s | 22M msg/s | 4.3× |
# 复现 iceoryx2 比较
cargo run --release --bin iceoryx2_comparison --features iceoryx2这才是我们敢放在首页的比较——因为两边都是我们自己跑出来的。
为什么内部测量表也被撤回了?
这里有两件完全独立的事情,不要混为一谈。
第一件: 那个 headline 倍数和它的比较表被撤回,因为 ROS 2 那一侧的数字是编造的。
第二件: 内部的"Measured Results"表格(1 kHz / 10 kHz / 100 kHz PASS 裁决)被撤回,原因和 ROS 2 毫无关系:
- 列出来的后端名字已经不存在了。 表格里写了
DirectChannel、SpscIntra、SpmcIntra、MpscIntra、MpmcIntra——这些后端全部被移除了。现在每个 topic 都是 SHM 支撑的,Topic::backend_name()只能返回PodShm、SpscShm、SpmcShm、MpscShm、FanoutShm或Unknown。 - 尾部被代码截断了。
Statistics::from_samples在计算max、p99、p99.9之前先跑了一个 Tukey IQR 滤波,所以报告出来的"最差情况"不可能超过 `Q3 + 1.5×IQR"——不管机器实际卡顿得多厉害。那个"最差测量 885 ns"的数字,是代码保证不可能大的数字。
这两件事的撤回原因完全不同。写第一件,原因就是编造的 ROS 2 数字。写第二件,原因就是不存在的后端和 IQR 截断的尾部。永远不要反过来讲,也不要把它们混成一个故事。
那些 per-message 数字呢?
robotics_messages_benchmark 在 i7-10750H 上跑出来的 send-only 数字是真实的:
| 消息类型 | 大小 | send-only 延迟 |
|---|---|---|
| CmdVel | 16 B | 75 ns |
| Imu | 304 B | 121 ns |
| JointCommand | 928 B | 135 ns |
| LaserScan | 1,480 B | 210 ns |
文档把这些数字换算成相对于 REP 2014 ~5 µs 参考值的约 67× / 41× / 37× / 24×。
但要注意: 这些是 send-only——它们测的是生产者把消息放进共享内存槽的开销,没有消费者在路径上。把它们和端到端延迟比较是指示性的,不是 benchmark 结果。如果你引用这些数字,请说清楚这一点。
所以 HORUS 到底快不快?
这个问题问错了。正确的问题是:对谁快、在什么场景下快、快在哪里?
- 如果你的瓶颈是 DDS 序列化 + 网络栈,HORUS 的共享内存环形缓冲区确实快很多——但我们对 ROS 2 能给出的诚实倍数只有约 30×(基于文献参考值,不是我们自己测的)。
- 如果你的瓶颈是 确定性调度,HORUS 有 5 个执行类、分级看门狗、预算和截止日期强制执行——这些跟延迟数字无关,但往往是真正的痛点。
- 如果你只是写一个简单的机器人教程节点,ROS 2 可能才是正确答案。HORUS 是性能中间件,不是初学者的第一个框架。
你该相信我们吗?
不该。至少不该盲目相信。
去跑那个 benchmark。看它打印出来的数字。检查 measurement 列——send 和 one-way 不是同一件事。检查 backend 列——如果你看到任何 *Intra 的名字,说明二进制版本不对。
# 完整的延迟基准,包含统计分析和后端检查
cargo run --release -p horus_benchmarks --bin all_paths_latency
# iceoryx2 对比(需要 iceoryx2 feature)
cargo run --release --bin iceoryx2_comparison --features iceoryx2
# 机器人消息类型基准
cargo run --release -p horus_benchmarks --bin robotics_messages_benchmarkall_paths_latency 会为每个场景打印一行,包含 scenario、backend 和 measurement 三列。如果 live backend 和预期不符,它会打印 MISMATCH——这个检查本该在撤回之前就抓住问题。
自己验证
- 仓库:https://github.com/softmata/horus
- Benchmark 源码:
benchmarks/目录 - 文档:https://docs.horusrobotics.dev/performance/benchmarks
- 复现命令:
cargo run --release -p horus_benchmarks --bin all_paths_latency(171 ns 端到端跨进程)cargo run --release --bin iceoryx2_comparison --features iceoryx2(vs iceoryx2,两边都测过)
在你自己的机器上跑。用 sudo cpupower frequency-set -g performance 把 CPU governor 切到 performance 模式。结果会因硬件和内核调度而异——这就是为什么我们给你命令,而不是给你一个数字。