Skip to content

第 20 章:为性能而设计

系列:软件设计的哲学 · 第 20/22 章
全书导读:00-overview.md


一句话总结

性能与简洁设计多数时候不冲突——先写清晰代码再 profile 定位热点;仅在 measured 瓶颈处做针对性优化,并注释牺牲之处。


核心观点浓缩

  • 过早优化是万恶之源仍成立,但「完全不想性能」也会锁死错误架构(如 O(n²) 数据模型)
  • 设计阶段选型:数据结构、缓存层级、I/O 批量 vs 逐条——这些事后难改
  • 流程:简单实现 → 基准/profile → 优化热点 → 保留测试
  • 许多优化通过更好算法与更少分配达成,非更晦涩代码
  • 性能改动应局部化并文档化,避免把整个模块变成不可读
  • 测量两次优化一次:确认瓶颈稳定复现再动刀,避免优化已消失的假想敌人
  • I/O bound 与 CPU bound 优化手段不同——profile 应区分等待计算

关键概念 / 金句

阶段做法
设计问量级:点数、并发、延迟 SLA;选对容器与边界
实现清晰第一;避免微观优化臆测
优化profile 指向函数;改前改后数字写进注释或 ADR

「简单设计常常足够快;复杂设计常常既慢又难改。」


本章在全书中的位置

第 20 章在取舍篇中处理性能 vs 复杂度张力,与第 18 章「局部可不 obvious」呼应。第 21 章将进一步说:并非所有性能目标都值得追——要决定什么重要。Ousterhout 反对两个极端:完全不考虑性能的设计,以及未测量就微观优化;中间路径是架构级审慎 + 热点级精准


个人思考与启发

点云融合曾用 std::map 按体素索引,百万点卡顿。profile 显示查找占 70%,换 unordered_map + 预 reserve 后吞吐升 5 倍,接口未变。若一开始为性能写自定义哈希表,维护成本会高得多。VTK 管线亦同:先 Update() 简单串接,profile 后再决定是否合并 Filter——清晰管线更利于定位哪一段吃 CPU。优化 PR 应附前后 benchmark 数字,否则难以在 Review 中辩护复杂度上升。性能 regress 与功能 regress 一样,应纳入 CI 或 nightly 基准。


与《程序员修炼之道》对照

  • 估算接近问题(profiler)——两书均强调数据驱动优化
  • 「足够快的软件」:定义 SLA 再优化,非无限压榨
  • 缓存、懒初始化等修炼之道技巧,应封装在深模块内(第 4 章)
  • 解耦与解耦过度:性能优化不应打破模块边界 unless profile 证明跨边界成本主导

重点与注意

重点:性能需求应量化(帧率、P99 延迟),否则无法判断「够快」。
重点:优化后保留正确性测试;性能 patch 是回归高发区。
注意:多线程优化引入的并发复杂度,常远超算力收益——先算法后并行。
注意:与第 16 章联动:性能 hack 也是复杂度债,需标注与偿还计划。
注意:移动端/嵌入式内存紧张时,设计阶段即纳入峰值内存预算,非事后 OOM 才改。
注意:GPU/VTK 管线优化先查不必要 Update,再谈 kernel 级微调。


导航第 19 章 软件潮流 · 下一篇:第 21 章 决定什么重要

基于 VitePress 强力驱动 | 记录技术与生活