Casey Muratori谈万恶之源:软件性能危机的深层根因

引言:一场直指行业软肋的演讲
在即将到来的 BSC 2026(Better Software Conference)上,知名软件工程师、性能优化专家 Casey Muratori 带来了一场名为《The Root of The Root of All Evil》(万恶之根源的根源)的演讲。这个标题化用了计算机科学界流传已久的名言——"过早优化是万恶之源"(Premature optimization is the root of all evil),通常被归功于 Donald Knuth。
BSC(Better Software Conference)是由 TechWell 公司组织的年度技术会议,其历史可以追溯到1980年代,最初以软件测试和质量保证为核心,后逐步扩展到涵盖整个软件工程生命周期的议题。该会议与 STAR(Software Testing Analysis & Review)等姊妹会议共同构成了北美地区最具影响力的软件质量会议群。与侧重于特定技术栈的会议不同,BSC 更关注跨越具体语言和框架的工程原则,通常涵盖测试、架构、性能、团队协作等议题,吸引的是关注软件工程基本功的从业者群体。
这句名言出自 Knuth 1974年发表的论文《Structured Programming with go to Statements》。Knuth 本人是计算机科学的泰斗级人物,《计算机程序设计艺术》(The Art of Computer Programming)的作者——这套著作被 Bill Gates 称为"如果你能读完整套书,绝对应该给我寄一份简历"——同时也是 TeX 排版系统的创造者。TeX 至今仍是学术出版的标准工具,其精确的数学排版能力在问世四十余年后依然无可替代,这本身就是 Knuth 对软件品质追求的明证。
值得注意的是,这句话的思想渊源可以追溯到 Tony Hoare。Hoare 是1980年图灵奖获得者,快速排序算法的发明者,CSP(Communicating Sequential Processes)并发模型的提出者,也是霍尔逻辑(Hoare Logic)的创建者。他对软件正确性和简洁性的追求贯穿其整个学术生涯,他曾说过"软件设计有两种方式:一种是使其足够简单以至于明显没有缺陷,另一种是使其足够复杂以至于没有明显的缺陷。"Knuth 在论文中也提到了 Hoare 对这一思想的贡献。
Knuth 写作这段话的背景是1970年代结构化编程运动的高潮期。这场运动由 Edsger Dijkstra 在1968年的著名信件《Go To Statement Considered Harmful》引发,深刻影响了编程语言设计和软件工程实践,推动了 Pascal、C 等结构化语言的普及。当时的争论焦点是 goto 语句的使用——支持者认为 goto 提供了灵活性和性能优势,反对者则认为它导致"意大利面条代码",使程序逻辑难以理解和验证。Knuth 的论文正是在这场激烈辩论中试图寻找平衡立场,既承认结构化编程的价值,又反对教条主义地完全禁止 goto。他的核心论点是:程序员不应在无关紧要的地方做微优化(比如为了省几个时钟周期而使用 goto 破坏代码结构),但同时必须对程序中真正的性能瓶颈保持警觉。这个语境在后来的传播中几乎完全丢失了。
Casey Muratori 长期以来以"反主流"的技术观点著称。他是《Handmade Hero》项目的作者,也是软件性能与底层工程领域极具影响力的布道者。《Handmade Hero》是 Casey 从2014年开始的一个大型直播编程项目,目标是从零开始、不使用任何第三方库(甚至不用标准库的大部分功能),完全手写一个完整的游戏引擎和游戏。整个过程通过直播和录像公开,每一行代码都有解释。这个项目不仅是一个技术展示,更是一种哲学宣言——它证明了一个人在理解底层机制的前提下,可以写出比大量依赖框架和引擎的团队更高效的代码。该项目累计超过600集,成为了底层编程教育的重要资源,也让 Casey 成为了"反抽象膨胀"运动的代表人物。这一运动的参与者还包括 Jonathan Blow、Mike Acton、Chandler Carruth 等人,他们共同构成了一个松散但有影响力的社群,主张程序员应当重新掌握对硬件的理解和控制权。
这次演讲的标题暗示,他要探讨的不仅是"万恶之源"本身,而是追溯到"根源的根源"——整个行业对性能问题认知偏差的深层原因。

"过早优化是万恶之源":一句被严重误用的格言
断章取义如何扭曲了Knuth的本意
在软件工程界,"过早优化是万恶之源"几乎成了一句免死金牌。无数开发者用它来为忽视性能、编写低效代码辩护。然而 Casey Muratori 长期以来的核心批判正在于此:这句话被严重误用了。
Knuth 的原话完整版本是:"我们应当忘记那些微小的效率提升,大约 97% 的情况下:过早优化是万恶之源。然而我们不应放过那关键的 3%。"换句话说,Knuth 从未主张开发者可以完全无视性能,他强调的是要在正确的地方投入优化精力,而非在所有细枝末节上过度纠结。这里的"97%"并非精确的统计数据,而是 Knuth 基于其丰富编程经验的一个估计——大多数代码只执行一次或很少执行,真正构成性能瓶颈的往往集中在很小一部分代码中。这与后来广为人知的"帕累托法则"(80/20法则)在性能分析领域的应用不谋而合:通常80%的执行时间花费在20%的代码上,甚至更为极端。
更重要的是,Knuth 紧接着还写道:"一个好的程序员不会因为这一理由而沾沾自喜,他会明智地仔细审视关键代码;但只有在这些代码被识别出来之后。"这段话清楚表明,Knuth 的立场是一种有策略的性能意识,而绝非对性能的漠视。他所倡导的是一种基于测量(profiling)的优化方法论——先用性能分析工具识别热点代码,再集中精力优化。这种方法论至今仍是性能工程的基本原则,现代工具如 Intel VTune、perf、Instruments 等都服务于这一目的。然而在数十年的传播过程中,只有那句"过早优化是万恶之源"被广为引用,完整的上下文和限定条件被系统性地遗忘了。
这种断章取义的传播模式在技术界并非孤例。Fred Brooks 的"没有银弹"(No Silver Bullet)被简化为"软件工程没有根本性突破";Dijkstra 关于 goto 的论述被简化为"goto 是有害的"——这些复杂而审慎的学术观点在社交媒体时代被压缩为口号式的教条,失去了原有的条件限定和思辨深度。
从"万恶之源"到"根源的根源"
Casey 此次演讲标题中"根源的根源"的表述,正是要挖掘更深一层的问题:为什么整个行业会普遍陷入这种认知误区?他一贯的观点是,现代软件开发文化系统性地贬低了对硬件、对性能、对底层机制的理解,导致了大量本可避免的性能浪费。
这种浪费并非空穴来风,有大量量化证据支撑。Nikita Prokopov 在其著名文章《Software Disenchantment》中列举了大量案例:Windows 95 在 30MB 内存上流畅运行,而现代操作系统需要数 GB;一个简单的聊天应用占用数百 MB 内存;网页加载的 JavaScript 代码动辄数 MB。Jonathan Blow(游戏《Braid》和《The Witness》的开发者,同时也是 Jai 编程语言的设计者——一种专为游戏开发设计的、强调编译期执行和性能的语言)也多次指出,如果按照硬件性能的提升比例,现代软件应该比实际表现快10到100倍。
为了量化这种差距:1995年的 Pentium Pro 运行于约200MHz,而2024年的顶级处理器运行于5GHz以上,时钟频率提升约25倍;加上指令级并行度的提升(超标量执行宽度从2-3提升到6-8)、缓存容量的指数级增长、多核并行能力,单机总计算能力提升了数千倍。然而,用户感知到的应用程序响应速度在许多日常任务上并未显著改善——文本编辑器的启动时间、邮件客户端的搜索速度、IDE 的代码补全延迟,在很多情况下甚至比二十年前更慢。
这种"性能负债"不仅浪费用户时间和电力,还直接影响碳排放。根据多项研究,全球数据中心的电力消耗约占全球总电力的1-2%,预计到2030年可能达到3-4%。如果软件效率提升仅10%,每年可节省的电力相当于数个中型国家的年消耗量。Intel 的研究表明,典型企业级应用仅利用了现代 CPU 能力的不到10%,大部分时间浪费在缓存未命中、分支预测失败和内存延迟等待上。据估计,低效软件每年造成的额外电力消耗相当于数百万吨碳排放。
Casey Muratori 的性能优化哲学
性能不是可选项,而是工程底线
作为性能优化领域的坚定倡导者,Casey 反复强调:现代计算机硬件的能力远超大多数软件所能发挥的水平。今天的 CPU 每秒可以执行数十亿条指令,但许多应用程序却因为糟糕的架构设计和对硬件的无知而变得异常缓慢。
以2024年的高端处理器为例,单核每秒可执行数十亿条指令,拥有多级缓存(L1缓存访问延迟约1纳秒,L2约3-5纳秒,L3约10-20纳秒),支持超标量执行、乱序执行、分支预测、SIMD 向量指令等复杂优化机制。SIMD(Single Instruction, Multiple Data)是一种并行计算架构,允许一条指令同时对多个数据元素执行相同操作。在 x86 平台上,从早期的 MMX 到 SSE、AVX、AVX-512 一路发展,最新的 AVX-512 可以在单条指令中同时处理16个32位浮点数或8个64位双精度浮点数。ARM 平台的 NEON 和 SVE 指令集也提供类似能力。正确使用 SIMD 可以将特定运算的吞吐量提升4到16倍,但这需要程序员确保数据对齐和连续存储——而这恰恰是面向数据设计所强调的。
然而,要充分利用这些特性,程序员需要理解缓存行(cache line,通常64字节——这是 CPU 与内存之间数据传输的最小单位,即使你只需要一个字节,CPU 也会加载整整64字节到缓存中)、内存对齐、分支预测失败的代价(通常10-20个时钟周期的流水线冲刷,在深流水线处理器上可能更多)等底层概念。现代 CPU 的分支预测器极其复杂,通常能达到95%以上的预测准确率,但当预测失败时,整个已经在流水线中部分执行的指令序列都必须被丢弃,处理器回退到正确的分支重新开始——这就是为什么无分支编程(branchless programming)在性能关键路径上如此重要。当软件通过多层抽象、虚函数调用、随机内存访问模式等方式运行时,CPU 的这些优化机制往往无法发挥作用,导致实际吞吐量可能只有理论峰值的百分之几。
他曾多次指出,很多开发者以"可维护性"、"抽象"、"开发效率"为名,构建了层层叠叠的抽象层,最终让软件运行得比几十年前的程序还慢。在著名的"Clean Code"辩论中,Casey 通过实际基准测试证明,按照 Robert C. Martin("Uncle Bob")在《Clean Code》一书中推荐的编码风格(小函数、多态替代条件判断、高度抽象)重构的代码,在某些情况下比简单直接的实现慢10到20倍。这引发了软件工程社区关于"代码整洁"与性能之间权衡的激烈讨论。这种现象在他看来,正是"过早优化是万恶之源"这句话被滥用的直接后果。
面向数据设计:回归硬件现实
Casey 是面向数据设计(Data-Oriented Design, DOD)理念的重要推动者之一。这一理念主张,程序员应当从数据在内存中如何布局、如何被 CPU 缓存和访问的角度来思考代码结构,而非仅仅从面向对象的抽象层面出发。
面向数据设计的核心洞见是:现代计算机的性能瓶颈往往不在计算本身,而在内存访问。这一现象被称为"内存墙"(Memory Wall),由 Wulf 和 McKee 在1995年的论文中首次系统阐述——CPU 计算速度的年增长率远高于内存访问速度的年增长率,二者之间的差距持续扩大。CPU 从主内存(DRAM)读取数据的延迟约为100纳秒,而从 L1 缓存读取仅需约1纳秒——差距达到100倍。这意味着,如果程序频繁访问不在缓存中的数据(cache miss),CPU 将大部分时间花在等待内存响应上,计算单元基本处于空闲状态。
DOD 主张使用结构体数组(Structure of Arrays, SoA)而非数组结构体(Array of Structures, AoS),确保同一操作需要的数据在内存中连续存储,从而最大化缓存命中率。举例来说,如果需要计算1000个粒子的位置更新,AoS 方式会将每个粒子的所有属性(位置、速度、颜色、生命周期等)放在一起,遍历时加载了大量不需要的数据;而 SoA 方式将所有粒子的 x 坐标放在一个连续数组中、y 坐标放在另一个数组中,遍历时每个缓存行都装满了即将使用的数据,缓存利用率接近100%。
在游戏开发领域,这一理念通过 ECS(Entity Component System)架构得到广泛应用。ECS 将游戏对象分解为实体(Entity,仅为一个 ID 标识符)、组件(Component,纯数据,无行为)和系统(System,纯逻辑,无状态)三部分。Unity 的 DOTS(Data-Oriented Technology Stack)和 Rust 语言的 Bevy 引擎都采用了这种架构。ECS 的核心优势在于,系统在处理数据时可以连续遍历同类型组件的内存块,实现接近理论极限的缓存利用率,相比传统 GameObject 模式可获得数量级的性能提升——Unity 官方的演示中,DOTS 版本在相同硬件上可以处理比传统方式多50到200倍的实体数量。Mike Acton(前 Insomniac Games 引擎总监,后来加入 Unity 领导 DOTS 项目)的著名演讲"Data-Oriented Design and C++"是这一领域的经典参考,他在演讲中提出的核心观点是:"如果你不了解你正在处理的数据,你就不了解你正在解决的问题。"
这种思路与主流软件工程教育中强调的封装、继承、多态形成了鲜明对比。面向对象编程(OOP)自1990年代起主导了软件工程教育和工业实践。其核心概念——封装(隐藏实现细节)、继承(代码复用的层次结构)、多态(通过虚函数表实现运行时分派)——为大型软件系统的组织提供了心智模型,在管理代码复杂性方面确实有其价值。但从性能角度看,OOP 的典型实现存在固有缺陷:对象通常通过 new 运算符在堆上分配,导致分散在内存各处(造成缓存不友好的随机访问模式);虚函数调用需要先读取对象的虚函数表指针,再通过虚函数表找到实际函数地址进行间接跳转(这破坏了 CPU 的分支预测和指令缓存,因为间接跳转目标在编译期不可知);深层继承树导致单个对象携带大量从未使用的父类数据成员(增加对象体积,降低缓存利用率)。
有趣的是,Alan Kay(OOP 概念的提出者之一,Smalltalk 语言的创造者,2003年图灵奖获得者)曾表示,他对 OOP 的设想是关于"消息传递"(messaging)的,而非关于"类和继承"的。他曾说:"我发明了'面向对象'这个术语,但我可以告诉你,我脑中想的不是 C++。"当前主流的 OOP 实践——特别是 C++ 和 Java 中以类继承为中心的范式——在很多方面偏离了 Kay 最初关于独立对象通过消息进行松耦合通信的设计意图,却造成了显著的性能开销。这也解释了为什么 Erlang、Elixir 等基于消息传递的语言,以及 Go 的接口机制和 Rust 的 trait 系统,都在试图以不同方式解决 OOP 继承模型的问题。
Casey 认为,正是主流范式对硬件现实的漠视,构成了性能问题的"根源"。
为什么这场演讲值得每位工程师关注
对软件行业文化的深层反思
Casey Muratori 选择在 BSC 这样一个关注软件工程基本功的场合发表演讲,暗示他的批判对象不仅是特定技术社区,而是整个软件工程文化。在这样的场合探讨"万恶之根源的根源",意味着 Casey 要触及的是行业文化层面的深层问题,而不只是具体的技术技巧。
这类讨论在当前尤其有现实意义。随着 AI 辅助编程、低代码平台的兴起,越来越多的代码在开发者甚至不理解其底层运作机制的情况下被生成。以 GitHub Copilot、GPT-4、Claude 等为代表的 AI 编程助手正在深刻改变代码的生产方式。据 GitHub 2023年的报告,Copilot 用户平均有46%的代码由 AI 生成;在某些语言和场景下这一比例更高。这些工具能快速生成功能正确的代码,但它们的训练数据主要来自互联网上已有的代码库(包括 GitHub 上数十亿行开源代码)——这些代码库本身往往充满了性能反模式。AI 生成的代码倾向于使用最"常见"而非最"高效"的解决方案,优先考虑可读性和通用性而非性能。例如,AI 可能在需要处理大量数据的场景中生成使用 Python 列表推导式而非 NumPy 向量化操作的代码,性能差距可达100倍。
更关键的是,当开发者不理解 AI 生成代码的底层行为时,他们失去了识别和修复性能问题的能力。这与"自动驾驶悖论"类似:当人类驾驶员过度依赖自动驾驶系统后,在需要接管的紧急时刻反而失去了必要的判断力和反应能力。这形成了一个恶性循环:低效代码被生成、被接受、被纳入训练数据,进而影响下一代 AI 工具的输出质量。随着越来越多的代码来自 AI 生成而非人类专家编写,训练数据的整体质量可能逐渐下降——这就是所谓的"模型崩溃"(model collapse)在代码领域的体现。
当抽象层进一步增厚,性能问题很可能被进一步掩盖。Casey 的批判在这个时代显得更加尖锐和必要。
快速迭代时代中一种稀缺的技术清醒
在软件行业普遍追求"快速迭代"、"先跑起来再说"的今天,Casey Muratori 代表了一种稀缺的声音——他坚持认为,理解你所使用的机器、尊重性能、写出高效的代码,不仅是一种工程美德,更是一种职业责任。
这种"先跑起来再说"的文化有其历史根源。精益创业(Lean Startup)方法论强调 MVP(最小可行产品),敏捷开发强调快速交付价值,这些方法论在商业层面确有其合理性——在产品市场契合度(Product-Market Fit)尚未验证之前,过度优化确实是浪费资源。问题在于,这种适用于产品探索阶段的方法论被不加区分地应用到了所有软件开发阶段,包括那些产品方向已经明确、用户规模已经确定的成熟系统。当一个应用拥有数亿用户时,每个不必要的毫秒延迟乘以数十亿次操作,就是天文数字的资源浪费。
他要追问的"根源的根源",或许正是:我们究竟是从什么时候开始,把对计算机本质的理解当作了可以外包给"框架"和"工具"的东西?这个问题的答案或许可以追溯到软件工程教育的转变——从早期强调算法、数据结构和计算机体系结构的课程设置,逐渐转向强调设计模式、框架使用和敏捷方法论。
这一转变大致发生在2000年代。在此之前,计算机科学教育通常包含汇编语言编程、操作系统内核实现、编译器构造等课程,学生被迫直接面对硬件的现实。而随着Java成为教学首选语言(始于1990年代末,到2000年代中期 Java 成为北美大学 CS101 课程最常用语言)、Web 开发的兴起、以及行业对"全栈工程师"的需求,课程设置逐渐向应用层倾斜。Carnegie Mellon、Stanford 等顶尖院校虽然保留了系统课程,但大量普通院校已经将计算机体系结构从必修课变为选修课,甚至完全取消。
当计算机科学专业的毕业生可以在不理解指针、内存管理甚至基本数据结构在物理层面如何运作的情况下进入行业,性能意识的缺失就不再是个人选择,而是系统性教育失败的结果。这也解释了为什么 Rust 语言的出现被许多系统程序员视为一线希望——它在语言层面强制程序员思考内存所有权和生命周期,某种程度上将部分底层意识"编码"进了语言本身的类型系统中。
结语
虽然这场演讲的完整内容有待 BSC 2026 正式呈现,但从标题和 Casey Muratori 一贯的技术立场来看,这无疑将是一次对软件行业主流认知的深刻挑战。它提醒我们,那些被奉为圭臬的格言,往往在被简化和传播的过程中丢失了最重要的语境。
对于每一位关心软件质量与性能的工程师而言,重新审视"过早优化是万恶之源"这句话的完整含义,也许正是理解现代软件性能危机的第一步。而 Casey 要我们思考的是更进一步的问题:当一个行业的主流文化系统性地回避对机器本质的理解时,我们失去的不仅是性能,还有作为工程师的基本判断力。
在一个计算设备无处不在、电力消耗持续增长、用户注意力日益稀缺的时代,软件性能不再仅仅是技术问题——它是经济问题、环境问题,甚至是伦理问题。每一行低效代码在数十亿设备上重复执行时,其累积效应远超任何单个程序员的想象。Casey Muratori 的追问因此具有了超越技术社区的普遍意义:我们是否有权让无知成为浪费的借口?
核心要点
相关推荐

干洗预测模型实战:从购物痛点到Serverless ML部署全流程
一位开发者因线上购物找不到洗涤标签,构建了完整的机器洗涤预测模型。本文复盘其AWS Serverless架构、Lambda冷启动问题、类别不平衡处理及MLflow模型管理的实战经验与工程妥协。

Web开发转型AI工程师:一条务实的进阶路径
从Web开发者转型为真正的AI工程师,不再局限于提示词工程。本文基于Reddit真实案例,梳理从夯实基础、吃透Transformer原理到工程化专精的三层进阶路线,附推荐课程与实操建议。

Gemini Omni Flash引热议:为何独缺Pro版?
Google发布Gemini Omni Flash却没有Pro版本,引发社区热议。从命名逻辑到行业趋势,解析Flash先行策略背后的商业考量,以及AI模型从性能竞赛转向效率优先的深层变化。