在程式碼審查中,你應該多少聽過「過早最佳化是萬惡之源」這句話。
但找來原文閱讀後,故事有些不同。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 真正想說的話。
如果今天有哪段程式碼因為「看起來好像很慢」而想修改,建議先執行一次分析器。

