很多人选择 Rust,是因为“快”。
但当你真的把 Rust 用在高并发、长生命周期、重负载系统里时,会发现一种很反直觉的现象:
Rust 的性能瓶颈,往往不在 CPU,而在你对抽象成本的误判。
而且其中不少问题,是 Rust 特有的。

1️⃣ Rust 的性能陷阱,很少来自“慢代码”
在 C/C++ 世界里,性能问题往往是:
- 算法不行
- cache miss
- 分支预测失败
- 内存布局糟糕
在 Rust 世界里,真正常见的反而是:
- 你引入了一个你以为“零成本”的抽象
- 但它在系统层面并不便宜
Rust 的抽象语义零成本 ≠ 系统零成本。
2️⃣ 第一个独有陷阱:Arc 泛滥带来的「原子风暴」
Arc 是 Rust 并发中最常见、也最容易被滥用的工具。
Arc<T>
你以为你只是“共享了一个对象”,但你实际引入的是:
- 原子引用计数
- cache line 争用
- drop 时的同步成本
- 跨线程内存可见性约束
典型症状
- CPU 使用率不高,但 QPS 上不去
- perf 显示大量时间在
atomic_add - 延迟抖动明显
Rust 的问题在于:
Arc 看起来太安全、太自然、太“无害”了。
3️⃣ 第二个独有陷阱:async 任务过度切分
你在 async Rust 中很容易写出:
tokio::spawn(async move {
do_a().await;
do_b().await;
});
在逻辑上,这看起来很优雅。
但在性能上,它意味着:
- 一个独立 task
- 一个调度节点
- 一组 waker
- 可能的跨线程迁移
Rust 特有的问题
在很多语言中:
- async task = 轻量 coroutine
在 Rust 中:
async task 是调度器管理的资源单元。
过度拆 task,会导致:
- 调度开销淹没业务逻辑
- cache locality 变差
- tail latency 变长
4️⃣ 第三个独有陷阱:Future 体积失控
你可能写过这种 async 函数:
async fn handle(req: Request) {
let big = BigStruct::new();
let cfg = load_cfg();
let conn = get_conn().await;
process(big, cfg, conn).await;
}
问题是:
在第一个 await 之前创建的所有变量,都会成为 Future 的字段。
这意味着:
- Future 被 move / poll / 存储
- 大对象被频繁搬运
- 内存占用膨胀
这在其他语言里几乎不可见,在 Rust 里却是硬成本。
5️⃣ 第四个独有陷阱:你写的“安全代码”,在偷偷分配
Rust 不喜欢隐藏分配,但生态层的抽象可能会。
常见来源:
collect::<Vec<_>>()to_string()format!clone()(尤其是 Arc / String / Vec)- 某些 iterator adaptor
在高频路径上:
一次你没注意的分配,可能比一次 syscall 更贵。
Rust 的问题是:
它给了你“显式控制”,但你必须真的去用。
6️⃣ 第五个独有陷阱:锁不是慢,锁竞争是慢
很多 Rust 开发者会有一个错觉:
“Mutex 在 Rust 里很安全,所以可以放心用。”
安全 ≠ 高性能。
Arc<Mutex<T>>
当你看到它时,真正的问题是:
- 锁保护了什么?
- 临界区有多大?
- 锁是不是跨 await?
- 锁是否在 hot path?
Rust 的类型系统无法帮你解决逻辑层面的锁设计问题。
7️⃣ Rust 性能调优的真正顺序
Rust 老手调性能,很少一开始就:
- 改 unsafe
- 写 SIMD
- 手写 allocator
真正的顺序通常是:
- 减少共享
- 减少分配
- 减少 task / future 数量
- 缩小 Future 体积
- 控制锁粒度
- 再考虑 unsafe / 底层优化
这是 Rust 独有的调优路径。
8️⃣ 为什么 Rust 的性能问题“出现得更早”
一个很重要但少有人说清的事实是:
Rust 的性能问题,往往在中等规模就暴露。
原因是:
- 抽象成本不会被 GC/VM 吞掉
- 并发调度成本是显式的
- 内存布局直接影响行为
这其实是好事。
因为你可以:
- 更早定位
- 更精确修复
- 更少“玄学调参”
9️⃣ 一个反直觉结论:Rust 慢,往往是你设计太“高级”
很多 Rust 性能事故,最后的结论是:
你把一个系统问题,包装成了一个优雅的抽象问题。
- Arc 代替结构拆分
- spawn 代替 pipeline
- trait object 代替枚举
- clone 代替所有权转移
Rust 不惩罚“底层”,它惩罚的是:
不清楚资源流向的设计。
结语:Rust 的性能,不奖励“感觉正确”,只奖励“结构正确”
Rust 是一门:
- 抽象能力极强
- 但几乎不宽容误用抽象的语言
它不会像 JVM 一样:
- 帮你合并对象
- 帮你消除分配
- 帮你重写调度
它只做一件事:
忠实执行你设计出来的系统。
这既是它的残酷之处,也是它在高可靠系统中不可替代的原因。