Rust:别让多 worktree 各编一遍
AI 并行开发最贵的一笔开销,常常不是模型,是 Rust 反复重编依赖。
现场:一台 8 核 Mac,两个 worktree 同时
cargo test。问题不在"两个 cargo",在每个 cargo 默认按逻辑核数拉编译器——十几个rustc一起上,机器开始疯狂换页(swap),编译本身没挂,但电脑已经没法正常办公。
四招,都要做。
1. 限并发:两个轴,缺一不可
大多数人只限了一半——只限"同时几个 cargo",忘了每个 cargo 自己还会 fan-out。
sem限同时几个 cargoCARGO_BUILD_JOBS限每个 cargo 拉几个 rustc。没有它,每个 cargo 按逻辑核数并发——这才是"2 个 cargo 变 15 个 rustc"的真因。
wrapper(heavy-cargo):
#!/bin/sh
# 8核/16GB:同一时间一个重型 cargo,每个 cargo 最多两个 rustc。
# 按 swap 调,别只看核数;32GB+ 可以试 sem -j 2。
exec sem --id rust-heavy -j 1 --fg -- \
env RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=2 \
nice -n 15 taskpolicy -b cargo "$@"
nice 降低 CPU 优先级;taskpolicy -b 设 Darwin 的后台调度策略(压后台任务的 CPU/I-O)。两者不严格等价 Linux 的 ionice,只是同一目的的平台手段。
2. 共享编译缓存(sccache)
sccache 让不同 worktree 复用编译产物。关键是 incremental:
.cargo/config.toml里[env] CARGO_INCREMENTAL = "0"不生效——[env]只把变量传给 cargo 启动的子进程,来不及影响 cargo 自己的增量决策。- 但启动前设
CARGO_INCREMENTAL=0 cargo …有效(上面 wrapper 就是这么干的)。好处:把"关 incremental"限定在重型构建,其他项目照常增量编译,不必全局牺牲。想全局关也行,用[build] incremental = false。
跨 worktree 命中的主要是第三方依赖(同一 registry、路径一致)。自有 crate 默认因绝对路径进了缓存键而不跨 worktree 命中——但新版 sccache 的 SCCACHE_BASEDIRS 能归一化不同 checkout 的路径:
SCCACHE_BASEDIRS="$PWD" RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0 cargo check
别承诺 100% 命中:bin、dylib、cdylib、proc-macro 这些要调链接器的 crate 本来就不能缓存。
务必验证真的生效,否则配了也不知道有没有用:
sccache --zero-stats
heavy-cargo test -p server
sccache --show-stats # 看 cache hits / requests executed
3. 各自独立 target,别共用
别为省空间把多个 worktree 指到同一个 CARGO_TARGET_DIR——会锁竞争,反而更慢。复用靠缓存,不靠共享 target。
4. 还想再快(按平台验证)
- 链接器:Linux 可试 mold / lld(链接阶段常吃掉一半时间);macOS 不要直接套 mold——mold 的 Rust 配置明确限
target_os = "linux",README 里的 Apple M1 测试跑的是 Fedora Asahi,不是 macOS。换链接器必须按目标平台单独验证。 - cargo-nextest 跑测试;dev profile 里
debug = "line-tables-only"砍调试信息体积。
最后:把约束钉进 AGENTS.md
工具装好了,agent 照样裸 cargo test,限流就等于没落地。写死一条:
重型 Rust build/test 必须通过 heavy-cargo;
agent 不得直接并发启动多个 cargo test。
一句话:限并发(两个轴)、共享缓存、隔离 target、按平台选链接器——再把规则钉进 AGENTS.md,AI 让你同时开三条线,电脑才扛得住。

微信
支付宝
评论
评论发布后会立即公开,如触发规则可能被审核下架。