编译时间优化
问题
Rust 编译太慢怎么办?有哪些优化手段?
答案
编译时间分析
# 查看各 crate 编译时间
cargo build --timings
# 生成 cargo-timing.html 报告
# 逐步分析
cargo build -Z timings # nightly
优化清单
| 优化手段 | 效果 | 说明 |
|---|---|---|
| 开发时用 debug 编译 | 显著 | 不要在开发时用 --release |
| 减少泛型单态化 | 中等 | 大型泛型函数提取非泛型部分 |
| 减少 derive 宏 | 中等 | 只 derive 需要的 trait |
| 使用 workspace | 中等 | 并行编译独立 crate |
| mold/lld 链接器 | 显著 | 替代默认链接器 |
| sccache | 显著 | 编译缓存,跨项目复用 |
| cargo-nextest | 显著 | 更快的测试运行器 |
快速配置
.cargo/config.toml
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[target.x86_64-apple-darwin]
rustflags = ["-C", "link-arg=-fuse-ld=/opt/homebrew/bin/ld64.lld"]
# 开发时优化级别
[profile.dev]
opt-level = 0
debug = true
# 依赖用更高优化级别(编译一次即可)
[profile.dev.package."*"]
opt-level = 2
减少泛型膨胀
// ❌ 每个不同的 T 都会生成一份代码
fn process<T: Display>(items: &[T]) {
for item in items {
println!("{}", item);
// ... 大量逻辑
}
}
// ✅ 提取非泛型部分
fn process<T: Display>(items: &[T]) {
for item in items {
process_inner(&item.to_string());
}
}
fn process_inner(s: &str) {
println!("{}", s);
// ... 大量逻辑(只编译一次)
}
常见面试问题
Q1: Rust 编译为什么慢?
答案:
- 泛型单态化:每个具体类型生成独立代码 → 编译代码量大
- 宏展开:过程宏(如 serde derive)可能生成大量代码
- LLVM 后端:优化阶段(特别是 LTO)非常耗时
- 借用检查:复杂的生命周期分析
- 链接:默认链接器慢(换 mold 可大幅改善)
最有效的优化:mold 链接器 + sccache + workspace 拆包。