在代码审查中,你应该至少听过一次“过早优化是万恶之源”这句话。
但找到原文读过之后,事情就有些不同了。Donald Knuth 绝不是在说“不要优化”。
先说结论:Knuth 说的是“忘掉97%的琐碎优化,但绝不要错过真正重要的3%”。常被引用的半句话把后半段完整地删掉了。
今天我们来整理这句话的真实语境,以及代码究竟应该在什么时候优化。
真正的原文是这样
这句话出自 Donald Knuth 于1974年撰写的一篇论文,标题是“Structured Programming with go to Statements”,发表在 ACM Computing Surveys 上。
原文如下。
“我们应该忘掉琐碎的效率,也就是说,大约97%的时间都应如此。过早优化是万恶之源。但在那关键的3%中,我们绝不能错过机会。”
看到了吗?我们熟悉的句子其实只截取了中间一段。
前面是“忘掉97%”,后面接着“不要错过3%”。这三句话是一个整体。
Knuth 不是说不要优化,而是说要选择把精力投入到哪里。
“忘掉97%,专注于3%”这才是核心
Knuth 在同一篇论文中还指出了另一点。
程序员为了担心程序中并不重要部分的速度,浪费了大量时间。
这种提前进行的优化反而会让调试和维护变得更加困难。
也就是说,问题不在于优化本身,而在于时机和位置。在还不知道瓶颈在哪里时就随意修改,才是祸根。
不是不要优化,而是不要毫无依据地到处优化。
那么究竟什么时候应该优化?
这是最常见的问题。答案很简单:测量之后再做。
找到 Knuth 所说的关键3%,靠的不是感觉,而是测量。运行性能分析器,找出实际消耗时间的地方,然后处理那里。
使用 Swift 时,可以先这样确认瓶颈。
// 测量实际是哪些代码消耗了时间
let clock = ContinuousClock()
let elapsed = clock.measure {
slowFunction()
}
print(elapsed) // 耗时较长的部分就是那个 '3%'
查看测量结果后,我们通常会发现自己的预期错了。以为会慢的地方其实没问题,反而是一个没想到的循环拖慢了整体。
这样区分过早优化和合理优化会更容易理解。
| 分类 | 过早优化 | 合理优化 |
|---|---|---|
| 时机 | 测量前,凭感觉 | 测量后,依据数据 |
| 对象 | 任何显眼的地方 | 确认是瓶颈的3% |
| 结果 | 代码只是变得更复杂 | 实际性能提升 |
还有一点:这句话可能根本不是 Knuth 说的
这里还有一段有趣的后续故事。
这句话也常被认为出自 Tony Hoare(C. A. R. Hoare)之口。许多常用的名言网站也把它列为 Hoare 的名言。
但 Knuth 本人在1989年的文章“The Errors of TeX”中,称它为“Hoare’s Dictum”。
而 Hoare 又说,这不是他的话,而是 Knuth 的话。
两位大师互相把出处推给对方;不过根据文献证据,主流观点认为这是 Knuth 的表述,首次出现在1974年的论文中。
无论最先是谁说的,重要的是它原本的含义被截成了一半并遭到误解。
常见问题
Q. 那是不是从一开始就不用在意性能?
不是。像算法选择这样决定结构的判断,从一开始就要考虑。Knuth 让我们忘掉的是“琐碎的”效率,而不是设计层面的决策。
Q. 什么时候测量?
先创建能运行的代码。先让它跑起来;如果速度慢,再用性能分析器找出瓶颈,只修复那个位置。
下次再遇到这句话时,也请想起后半句:忘掉97%,但不要错过3%。
警惕未经测量就进行优化,但面对真正的瓶颈也不要退缩。这就是 Knuth 真正想表达的意思。
如果今天有哪段代码因为“感觉很慢”而想修改,建议先运行一次性能分析器。

