软件再也没有理由慢下去了
文章摘要
Dan Luu 这篇文章的核心论点是:性能优化的成本已经下降了好几个数量级,因此过去那些「不值得做」的优化,现在都值得做了。他明确声明这是一篇「快速、不严谨」的实验记录(他给自己定的目标是半小时写完,并承认超时了),而不是严格的研究。
文章的起点是一条走红的推文,嘲讽那些说「LLM 正在制造缓慢臃肿的代码」的人,说等 LLM 把一切都用超优化汇编重写时他们就要打脸了。Dan Luu 认为我们还没到「用汇编写一切」的地步,但 Nolan Lawson 关于测试的那句话——「你现在可以自己选择要多少 bug」——正越来越适用于性能领域。他引用了 Marc Brooker 的回应:「针对特定工作负载而非某一类工作负载的动态定制软件,看起来是个非常可能的结局」,Brooker 把这类比为 FFTW,以及大量 demoscene 的老技巧(他记得有个 demo 把自己的代码复用为纹理来获得极好的缓存局部性)。Michael Malis 则针对「AI 帮不上忙,因为写代码从来不是难点」这一流行说法反驳道:在某些领域写代码确实就是难点,JIT 编译器就是绝佳例子——很多软件用上 JIT 会快很多,而 JIT 之稀少恰恰说明它历史上难到不值得做;LLM 降低了门槛,这正是 pgrust 项目的立论基础。
实验一:给 ripgrep 加一个后台原生代码编译器。 前一篇文章里,Dan Luu 让 agent 循环迭代一个月造出了正则引擎 FRE(用 rebar 基准套件),结果严重过拟合到 rebar,直到警告 agent 存在保留集(holdout)后才泛化到「还行」的水平。但 FRE 的 AOT 原生编译版本在长搜索上表现不错。于是他想:可以在 ripgrep 跑常规匹配器的同时,另开一个线程跑原生代码编译,编译完成后切换过去。这会牺牲短查询的性能(丢一个线程给编译),但他更在乎 ripgrep 跑几秒到几分钟时的耗时。他只花了几分钟打了几句话,agent 就完成了这次「对人类来说算是不小的代码手术」,并用他 codex 历史里的真实 ripgrep 查询跑了基准。结果:少数简单长查询有 2 到 4 倍提升,但在更有代表性的保留查询上,只有约 7% 的加速。「不是石破天惊的结果,但对几分钟打字来说不算差。」
实验二:针对个人工作负载做定制优化。 在动笔写这篇文章前,他花约两分钟启动了一个 agent,让它针对自己的 ripgrep 查询优化 FRE 引擎,用一组查询训练、另一组保留查询验证。一轮优化后,工作负载定制版在保留集上比标准 ripgrep 快 2%,而且还在继续变快。2% 对他个人使用来说无关紧要,但重点是这只花了几分钟——而且这是建立在 FRE 这个在通用保留基准上明显慢于 Rust regex crate 的引擎之上的。他的洞察是:他不懂正则工作负载,SOTA 模型也不擅长实验设计,所以无法做无引导的开放式自我改进;但如果只关心自己的工作负载,他有的是数据,而且还在不断产生。他建议 Marc Brooker(亚马逊)或 Michael Malis(pgrust)这样的人不要只做一次性尝试,而应和客户合作试点,用客户数据为其定制优化,再规模化推广。
旁证一:Azul 棋类 AI。 在 GPT-5.1/5.2 时代,他在完全不懂游戏 AI 的情况下做了一个 Azul AI,结果成为该游戏世界最强的 AI,且优势很大。读过描述第二强 AI 的那篇论文后,他认为自己在「AI」层面可能略好一点,但主要胜在优化——而他花的时间估计少了两个数量级,而且主要在笔记本上跑(对方有集群)。比如对方是单线程的,他的是多线程的。他既有原生版本又有一个「骇人的共享 wasm 内存 + JavaScript」版本,两种搜索架构(小网络快模型用 minimax,大网络用 MCTS)需要完全不同的多线程算法。他还提到一个关键细节:为了调试和验证非确定性的多线程算法,需要实现「从调试日志重放以复现 bug」这类基础设施,手写大概要几天到一周,但这正是 agent 可以轻松循环搞定的事(每次重放不完美就插入日志找非确定性来源)。他补充说游戏 AI 比一般软件麻烦,因为很多优化会改变结果,没有便宜的办法判断「提速 + 结果变化」的净效果好坏,所以他必须自己搭好那套判定框架。经验数据是速度每翻一倍约涨 100 Elo(比国际象棋高,他猜是因为和棋极少),光加多线程就足以碾压一个可比的对手。
旁证二:Jamie Brandon 与 Anthropic 的性能考题。 Jamie Brandon 为性能岗位面试做准备,尝试了 Anthropic 现已公开的性能 takehome,之后让 Claude 接着他的进度继续做,结果好得多。他检查 Claude 做了什么而自己没做时说,很多优化是他想到过但还没来得及做的,「其他一些则纯粹是疯狂的玩意儿,除非我在这上面干几周,否则我永远不会去试」。Dan Luu 补充:担心「接着人类的成果继续做」不公平,所以他又给了 agent 一个全新的任务,得分和 Jamie 那次差不多(另一个 agent 快速检查也没发现作弊证据)。他的结论是:Jamie 是个称职的性能工程师并拿到了心仪的 offer,但在一个边界清晰的优化问题上,他打不过一个像样的模型。
附录中的核心态度转变(也是标题的出处):Dan Luu 长期以来公开反对「写出慢软件的开发者很糟糕、应该感到羞愧」这种论调——编程专业性有很多种,大多数程序员没有性能专长,而且从生意和就业市场角度看,他们去发展这种专长可能本来就不合算。他打了个自嘲的比方:如果他去看「UI 能做到多好」和「他自己手工能做出多好的 UI」之间的差距,那看起来一点也不比性能差距更不荒谬,但他也不认为自己该花时间去学做好 UI。现在他的立场变了:他仍然不认为软件慢的人应该感到羞愧,但他认为一个完全不懂性能、只是 LLM 用得还行的普通人,现在通常应该能做出性能过得去的软件。「性能不再是一项专门技能了。」他也承认,如果你只是让 LLM「优化」,它会干各种非常糟糕的错事需要你抓出来——但这本来就是有效使用 LLM 的常态。他还提到自己给博客插入交互式图表后前端指标变差了,让 LLM 花掉他每周额度的 1% 就把 LCP、CLS 等指标优化回来了。
附录中的数据(codex 是怎么用 ripgrep 的)很有意思:他统计了自己机器上一个月的 ripgrep 查询分布。模式长度的中位数是 55 个 Unicode 码点,p90 达到 119——远比人手敲的长。最长的那些查询大多是函数名或测试名的超长交替(alternation),比如一个由几十个 fn (test_name_a|test_name_b|...) 组成的巨型正则。还有一些「有趣的数值构造」,比如一个把 130 到 999 用 87 个分支硬列出来的正则,等价于简洁得多的 :(?:1[3-9]|[2-9][0-9])[0-9] 加个重复量词——实测两者性能几乎一样(简洁版在真实数据上略快一点点)。产生这个查询的完整管线是 cargo clippy … | rg 'crates/fre-aot-regex/src/module.rs:' | rg NUMBER_REGEX | head -250,他评论道「人类可能不会这么干,但 agent 好像总在干这种事」。耗时方面很惊人:p99 接近 1 分钟,p999 接近 10 分钟,这段时期内最慢的一次查询接近 2 小时。局部性方面:约 94% 的模式只出现过一次(模式局部性极低),但被搜索的文件局部性相当高,刚搜过的文件很可能很快再被搜(意味着小文件很可能命中内存)。另外 99% 的查询是正则查询,99.9% 的搜索模式是纯 ASCII,但被搜索的文件里约 55% 含 Unicode,比他预想的高。Peter Geoghegan 提醒说,正则实现也可以通过「支持更少特性」来变快(比如不支持反向引用),这一点在这里同样成立——他这次的工作负载定制优化相当表层,因为他只给了 codex 简短指令让它自由发挥,如果给出更详细的计划、针对常见用例做更聚焦的优化,收益应当更大。
HN 评论精华
668 分、491 条评论。这场讨论的实际走向与文章论点基本是对立的:绝大多数高票评论并不接受「所以软件会变快」的推论,而是从各个角度论证「慢的原因从来就不是能力不足,而是激励结构」。此外还有一条相当长的支线在吐槽 Dan Luu 网站本身的排版。
最核心的反驳:瓶颈从来不在实现成本。 rbehrends 写了本帖最有分量的一条长评,把性能工程成本拆成三部分:(1) 定位性能问题的根因;(2) 实现;(3) 架构影响(性能是典型的横切关注点)。「文章似乎完全聚焦在第二点,而基本忽略了另外两点。」他引用三篇实证研究指出,大多数性能 bug 修起来并不难,难的是发现它们——实现工作量根本不是限制因素;反过来,另一些性能改进会影响整体设计(某研究中占所识别问题的 27%)。「拥有一个明确、自包含的优化目标,配一个基准测试,而且模块内的算法优化恰好就是关键问题——这是例外,不是常态。」他承认 agent 在这里也能帮忙(比如识别 profiler 里看不出来的瓶颈、快速做架构方案的对比评估),但强调解决这类问题不像正则那样是「爬山」,而是解谜和设计判断的结合,还涉及大量权衡:性能 vs. 架构简洁性、系统这部分的性能 vs. 那部分的性能。
voidhorse 说得更直接:「软件从来就没有理由慢。在我看来,我们有慢软件不是因为优化知识稀缺——大多数编译器优化得已经足够好了,只要你算法选对——而是因为其他激励比性能更强。」killbot5000 一句话概括:「只要实验(迭代速度)和性能之间还存在取舍,软件就永远会稍微慢那么一点。」bell-cot 提醒:按「给软件公司带来的利润」加权,绝大多数用户根本不在乎慢。0xbadcafebee 补充:「『没有理由』和『我们现在能更容易地做这件事』是两码事。仍然有一大堆让软件慢的理由,最大的是优先级。」他给出的极端处方是:「如果你想要更快更高效的软件,强迫它跑在 100MHz CPU、512KB 内存和 56k 调制解调器上。那时你绝对会优先考虑速度。」
「token 预算就是新的人力预算」。 phtrivier 提出了本帖最有说服力的结构性论证:文章作者身处一个可以随便烧 token 的处境,但这不普遍。即便不算环境影响,token 也是钱,总有人非常在乎这笔钱。他预见开发者将不得不分配固定的 token 预算,届时面对「烧 token 给明天演示加个客户要的新功能」和「烧 token 也许能让 app 在某个边缘情况快一点」,取舍会和过去分配人力时一模一样。「这个论证的前提是 token 不会大幅变便宜。我预测不了未来,但我看不到那条路径——我倒是能清楚看到 token 大幅变贵的路径(等 Anthropic IPO 六个月后我们再来看)。」bensyverson 用一句话总结了同样的意思:「和安全一样,优化现在是 token 支出的函数——某种意义上也就是『在不在乎』的函数。软件之所以可能继续比它能达到的更慢、更不安全,只是因为没人在乎到愿意投入时间和金钱去改进。」devin 呼应道:「不会是因为我们做不到。这将比以往任何时候都容易做到,但买 token 的钱当然会流向生意的其他方面。产品越做越差似乎是条铁律。」
内存涨价这个意外变量。 多位评论者(supriyo-biswas、unlimit、Grombobulous、WCSTombs)提到 AI 热潮引发的内存涨价可能反而是推动高效软件的真正力量。Grombobulous 举 iOS 27 为例说它在老手机上比上一版更快。但立刻有人反驳:wlesieutre 问「是 iOS 27 特别厉害,还是 iOS 26 是坨垃圾?」senderista 说「它最好是更快,iOS 26 基本上把我的 iPhone SE 变砖了」。有一条评论甚至反过来把矛头指向 LLM 本身:「LLM 造成了如此严重的内存涨价,以至于 pine64 不再生产 Linux 机器了。当你因为 LLM 的直接后果而买不起内存时,你的汇编 app 也会变慢。抱歉,这就是你选择的未来。」jongjong 则悲观地说他整个职业生涯都在盼这一天,但从未等到:「有时感觉宇宙间的一切都被调校成确保熟练软件工程师过着充满痛苦、挫折和无力感的生活。」
关于 LLM 能不能真的优化,正反两方都有第一手数据。 jeffbee 是怀疑派代表:「很少有人类能高效地做软件优化,所以我对人类造的机器也不乐观。我遇到的每一次 agent 优化,都是在往现有代码库上套一堆神话——循环展开、消除表面上的分支、SIMD——看着很酷但毫无意义,因为唯一可信的优化本该来自减少 load 数、少占 iTLB 槽位这类事情。」他想要的是「把 PMU(性能监控单元)拉进循环里」。但 tekne 给出了相反的一手证据:「样本量为一,但在几个月的毫无用处之后,我确实用 AI 优化拿到了相当严肃、可测量的性能提升——把耗时数天的关键业务流程加速了一个数量级,还有显著的延迟下降。但你需要一套非常扎实的工作流、能快速跑完的可靠基准,还有大量 token,外加严格的 profiling 流程。」gravypod 也提供了正面案例:他做一个下载批量数据、建索引、提供 Web UI 的项目,过去会直接上 sqlite 并觉得「够快了」,这次让 agent 打包文本并构建前缀树做搜索栏自动补全,「我以前也能做,但我不会去做」。他的总结很到位:「工程师现在有了很多以前因人力成本太高而不会去拧的性能旋钮。因为我们约束了 agent 的职责范围,slop 问题就没那么严重——我们把它限制在定义明确、有清晰 API 边界和测试框架的任务里。」
「维护性怎么办」是另一条被忽视的成本。 squirrellous 指出文章没提的一点:让 AI 激进优化的结果是代码复杂/精巧到原作者根本维护不了。「对于像正则引擎这种 API 极稳定、能测到死的东西,这大概行得通。别的东西就未必了。我们光是维护没有激进优化的 AI 生成代码就已经够头疼了!」
关于「测试套件就是可执行规范」的争论。 y1n0 提出「一切都取决于测试套件,测试套件成为可执行的规范,规范越好,AI 给的结果越好」。moron4hire 反驳:「如果你有那样的测试套件,你其实根本不需要 AI 帮你写代码。」thorian1828i03 给出了本帖最好的一个区分:写一个基准测试比写优化容易 100 到 1000 倍——基准可以简单到就是一个循环调用被测函数,而真正优化那个函数要难得多。mlsu 的哲学式反驳同样精彩:「测试套件和代码是同一个东西,只是从另一侧接近。……如果你有代码,写出完美测试它的测试是平凡的;如果你有测试,写出完美通过它们的代码也是平凡的。然而这一切都和代码或测试是否『好』无关,拥有其中一个的糟糕版本,并不能帮你写出另一个的好版本。」devin 补充了一个现实观察:很多人用 AI 做的第一件事就是宣布它写的自动化测试「足够好地」捕获了期望行为——写测试对大多数人不好玩——于是那个本该防止软件退化成垃圾堆的东西,在 vibe 出来的代码库里成了最被忽视的部分之一。
语言选择之争。 rfgplk 抛出了本帖最激进的观点:「LLM 基本上让 C++/Rust 系统级之上的所有语言都过时了。你之所以选 C# 或 Python,往往是图生态广,或者因为低级语言太难掌握、坑太多。现在这些理由都死了。」他建议大家试着让 LLM 写 SaaS 时不用经典的「给我设计个 app」,而是指定 C++ 或 Rust、尽可能用 SIMD 内建函数和内联汇编,「光这两条指令带来的代码质量差异就非常惊人」。反对声音密集:raincole 讽刺道「在团队本来就写不好 C++ 的情况下让 LLM 写 C++,这肯定比人写的 C# 和 Python 更安全」;dkersten 说「你的体验和我的不符,它写的是还行的代码,不是好代码。我看到它在桌上留下大量性能,做些傻事比如把所有东西包进一个全局互斥锁,在 Rust 或 C++ 里当然也写不出地道代码」;greg7gkb 追问:这个视角对已有应用、对前端应用(几乎从不用低级语言)有什么帮助?
网络才是真瓶颈。 ehnto 的高票评论指出:软件慢最大的原因之一就是在等网络请求,而如此多的软件要么在线、要么用同一套技术栈搭成,导致它们常年处于阻塞等待状态。「不在美国的人感受更深,网上那么多东西托管在美国,每次小交互 300ms,累积得飞快。如果你的软件为很多 UI 控件都配了等待对话框或加载转圈,你就是在按默认阻塞的假设构建。」由此引出一条关于「用动画掩盖延迟」的激烈争论:alightsoul 主张动画和插页能让用户感觉「后台在发生事情」,甚至认为有时必须故意加延迟「给电脑思考的时间」才能让人信任;lazide 强烈反对:「高级用户绝对痛恨这种心态。它导致 Apple 的动画要花好几秒去做一件在动画开始前就已经完成的事。」0cf8612b2e1e 举例:「iOS 里归档邮件的延迟令人难以置信,即便关掉动画,选中并移动一封邮件也要一秒多。」jbstack 则从根上反驳:「如果你的 app 真的必须每次交互都依赖云,那行。如果不是,你只是在给自己制造的问题贴创可贴。很多 app 完全可以做成本地优先。」这条支线又衍生出关于预取、Speculation Rules API、内容寻址 Web 的长篇讨论,其中 zanderwohl 提到 McMaster-Carr 网站悬停时预取全部链接,inigyou 举了个更极端的例子:某德国电子元件网站首次打开就下载整个目录(解压后约 2MB),此后点击和搜索都是瞬时的,因为下单前全在客户端。
关于网站排版的元讨论。 tobinfekkes 说「我浏览器的阅读模式救了我的命,否则我会立刻离开」,引发了长串争论。有人指出这违反了 HN 指南中「不要抱怨文章或网站格式这类边缘烦恼」的条款。markdown 尖锐地认为这是虚荣心:「他以前有个能用的网站,这个是故意做成烂的,一种『看我多极客』的姿态」,并贴出三行 CSS 引用说三分钟就能修好。userbinator 完全相反:「这个页面正是我希望大多数网站的样子:没有废话,没有愚蠢的『现代设计』潮流跟风,只有纯粹简单的内容。」vessenes 给出了最平衡的看法:「我喜欢 Dan 的网站,它符合他的气质和优先级。我随时可以用两个按键选好浏览器宽度和字号,而且我永远不必和他关于『我该怎么阅读』的想法搏斗。」tobinfekkes 后来补充说明他在 17 寸桌面显示器上,「读 100% 宽度的黑底白色小字几乎不可能」,在手机上则完全没问题。多条评论(0xblinq、jmalicki、rambambram、formvoltron、vagab0nd)都用标题句式开了同一个玩笑:「网站再也没有理由这么丑了。」
其他值得一提的观点。 gr_norm 给出了文章标题最需要的限定条件:「这需要加上『在你对软件该做什么有一份规范的前提下』。规范越好,你能给优化器的自由度就越大。」nemothekid 说这对正则引擎这种可验证任务成立,但别的就像「做出 GTA 6,别犯错」——你写出快而正确的软件的能力,取决于你能把问题说明到多清楚。belZaah 指出大系统的慢不在单个代码片段,而在架构如何动态响应负载变化——同步 vs. 异步调用、缓冲、并行 vs. 顺序处理,「大多数开发者没法条理清晰地(带数学、图表和数字地)解释连接池如何防止请求短时尖峰的不良后果,我也很确定 AI 不能」。4lx87 给出了本帖被认为最准确的一条元判断:「杰文斯悖论意味着我们会得到更多快软件,也会得到更多慢软件。斯特金定律意味着比例不变——出货的东西里 90% 会是又慢又有 bug 的垃圾,和 LLM 之前一样。」paulhebert 追问:AI 会不会改变那个 90%?「从我的角度看,糟糕的比例已经上升了。我没在『好』的那一侧看到同样大的影响——有注意力和匠心的人能用它做出很棒的结果,但他们的产出速度赶不上倒垃圾的人。」tomxor 提到一个有趣的反例:文章拿 demoscene 举例很有意思,但他试过让各种 LLM 解释或修改他的 demo,全都惨败——「在极端情况下,这种编码风格要求你把从头到尾发生的一切都装在脑子里,这种透视能力让你能在不被抽象拖累的情况下思考基本原理。」toephu2 则被文章里那句话触动:「Jamie Brandon 拿到了 Anthropic 的 offer,而除非你是 OpenAI,否则你大概雇不起他。」