name: m10-performance description: “关键:用于性能优化。触发词:性能、优化、基准测试、性能剖析、火焰图、基准、慢、快、内存分配、缓存、SIMD、让它更快、性能优化、基准测试” user-invocable: false
性能优化
第二层:设计选择
核心问题
瓶颈是什么,优化是否值得?
优化之前:
- 你测量过了吗?(不要猜测)
- 可接受的性能标准是什么?
- 优化会增加复杂性吗?
性能决策 → 实现
| 目标 | 设计选择 | 实现方式 |
|---|---|---|
| 减少内存分配 | 预分配,复用 | with_capacity,对象池 |
| 改善缓存 | 连续数据 | Vec, SmallVec |
| 并行化 | 数据并行 | rayon,线程 |
| 避免拷贝 | 零拷贝 | 引用, Cow<T> |
| 减少间接引用 | 内联数据 | smallvec,数组 |
思考提示
优化之前:
-
你测量过了吗?
- 先剖析 → 火焰图,perf
- 基准测试 → criterion,cargo bench
- 识别真正的热点
-
优先级是什么?
- 算法(10倍-1000倍提升)
- 数据结构(2倍-10倍)
- 内存分配(2倍-5倍)
- 缓存(1.5倍-3倍)
-
权衡是什么?
- 复杂度 vs 速度
- 内存 vs CPU
- 延迟 vs 吞吐量
向上追溯 ↑
到领域约束(第三层):
"这需要多快?"
↑ 询问:性能SLA是什么?
↑ 检查:domain-*(延迟要求)
↑ 检查:业务需求(可接受的响应时间)
| 问题 | 追溯至 | 询问 |
|---|---|---|
| 延迟要求 | domain-* | 可接受的响应时间是多少? |
| 吞吐量需求 | domain-* | 每秒多少请求? |
| 内存约束 | domain-* | 内存预算是多少? |
向下追溯 ↓
到实现(第一层):
"需要减少内存分配"
↓ m01-ownership:使用引用,避免clone
↓ m02-resource:使用with_capacity预分配
"需要并行化"
↓ m07-concurrency:选择rayon或线程
↓ m07-concurrency:考虑异步用于I/O密集型任务
"需要缓存效率"
↓ 数据布局:可能时优先使用Vec而非HashMap
↓ 访问模式:顺序访问优于随机访问
快速参考
| 工具 | 用途 |
|---|---|
cargo bench |
微基准测试 |
criterion |
统计基准测试 |
perf / flamegraph |
CPU性能剖析 |
heaptrack |
内存分配追踪 |
valgrind / cachegrind |
缓存分析 |
优化优先级
1. 算法选择 (10倍 - 1000倍)
2. 数据结构 (2倍 - 10倍)
3. 减少内存分配 (2倍 - 5倍)
4. 缓存优化 (1.5倍 - 3倍)
5. SIMD/并行化 (2倍 - 8倍)
常用技术
| 技术 | 适用场景 | 如何做 |
|---|---|---|
| 预分配 | 已知大小 | Vec::with_capacity(n) |
| 避免克隆 | 热点路径 | 使用引用或 Cow<T> |
| 批量操作 | 许多小操作 | 收集然后处理 |
| SmallVec | 通常较小 | smallvec::SmallVec<[T; N]> |
| 内联缓冲区 | 固定大小数据 | 数组优于Vec |
常见错误
| 错误 | 为何错误 | 更好的做法 |
|---|---|---|
| 未剖析就优化 | 目标错误 | 先剖析 |
| 在调试模式下基准测试 | 无意义 | 始终使用 --release |
| 使用LinkedList | 缓存不友好 | Vec 或 VecDeque |
隐藏的 .clone() |
不必要的分配 | 使用引用 |
| 过早优化 | 浪费精力 | 先让它工作起来 |
反模式
| 反模式 | 为何不好 | 更好的做法 |
|---|---|---|
| 克隆以避免生命周期 | 性能成本 | 正确的所有权管理 |
| 什么都用Box包装 | 间接引用成本 | 可能时使用栈 |
| 对小集合使用HashMap | 开销大 | 使用Vec进行线性搜索 |
| 在循环中拼接字符串 | O(n^2) | String::with_capacity 或 format! |
相关技能
| 场景 | 参见 |
|---|---|
| 减少克隆 | m01-ownership |
| 并发选项 | m07-concurrency |
| 智能指针选择 | m02-resource |
| 领域需求 | domain-* |