AI Pulse

AI 用 Rust 重写软件提速?一位开发者:慢在设计,不在语言

软件慢是因为糟糕的设计,而非慢语言

很多人说,AI 会通过用更快的语言重写软件来让它变快,但这并不是普遍成立的。大多数程序无法通过用 C 或 Rust 重写来获得有意义的加速。

这怎么可能?有些语言比另一些快几个数量级:比如,C 可以比 Python 快五十倍。那用 C 重写我的 Python 程序,不就也能快五十倍吗?不,不会。软件性能通常由 I/O 主导,而不是语言速度。在语言速度确实重要的地方,大多数慢语言已经有了流行的库,可以解锁接近 C 的速度。总的来说,性能是设计问题,而不是语言选择问题。

大多数真实程序是 I/O 密集型

考虑一个带数据库的简单 CRUD 网站。对于任何一次请求,50% 的请求时间¹可能花在查询数据库上:获取当前用户、被请求的记录、相关的用户成员资格或设置,等等。用 C 重写这个网站,只能加速另外那 50%,这给你能取得的改进设置了一个硬性上限²。最好情况下,你能让请求快一倍(实际上可能更接近 1.5 倍)。这不算差,但远远达不到一个数量级的加速。

换句话说,大多数真实程序是“I/O 密集型”的:它们大部分时间花在等待某个地方的数据输入或输出,而不是像“CPU 密集型”程序那样,大部分时间在积极地做事。I/O 密集型程序并不只是依赖数据库这一种情况。程序常常要等待第三方 API,或者等待向磁盘写入或读取数据。就算你把 curl 里的代码加快 100 倍,你大概也注意不到,因为 curl 把所有时间都花在等待网络上。

慢语言已经把工作委托给快语言

那明显不是 I/O 密集型的工作呢?比如,维基需要把存储的 markdown 转换成可渲染的 HTML³。用更快的语言重写这部分,不就能带来巨大的加速吗?确实会!这就是为什么做这种事的应用会使用像 cmark-gfm 这样的库,调用快语言来渲染 markdown。总的来说,大多数慢语言可以通过调用这类库写出非常快的程序。Python 是出了名的慢语言,但它在机器学习和数学这类 CPU 密集型工作负载上却是有竞争力的选择,因为它有一大批库,可以把这些工作负载委托给快速的 C 代码。如果一个 Python 程序把 80% 的时间花在 GPU 上做矩阵乘法,你用 C 重写它也不太可能让它变快,因为这些矩阵乘法已经发生在高度优化的 C 或汇编代码里了。

当然,有些程序确实在慢语言里做了大量 CPU 密集型工作。如果一个程序没得到多少工程上的关注,那很可能有很多唾手可得的机会。但这些程序往往不重要:如果它们重要,在 AI 让它变得(相对)容易之前,早就有人进去把它们优化好了。这并不意味着找不到有用的程序来重写。Actual Computer 最近用汇编重写了 tiktoken,带来了显著的加速⁴。然而,你不会这样去革新某个计算领域。即使是快速的 tokenization,也只在边缘上有用,因为花在 tokenization 上的时间只是推理时间的一小部分。

加速软件通常需要重新设计

尽管如此,我认为大多数软件比其本应达到的速度慢得多。我对显著加速常用软件的潜力(无论有没有 AI)感到乐观。但我认为这些加速大部分将来自重新设计程序,而不是用更快的语言重写它。

在 2018 年的一篇帖子中,Bryan Cantrill 描述了他试图把一个 C 程序重写成 Rust 的经历。这很困难,因为那个 C 程序精心优化的设计与 Rust 的借用检查器不太合得来。他放弃了,索性用 Rust 以朴素的方式写了这个程序,预期会慢 20% 甚至更多。结果反而快了 30%。原因归结为 Rust 内部更喜欢用 B-tree 而不是二叉搜索树,而 B-tree 恰好是一种缓存效率更高的数据结构。所以即使在很大程度上是 CPU 密集型的工作负载中,在非常擅长写快速 C 代码的人手里,性能也由设计主导,而不是语言速度。

这与我自己在高级语言方面的经验相符。回顾我取得过的显著加速,它们几乎无一例外都是对软件进行重新设计,让它做更少的工作:

- 缓存慢操作(通常是外部 API 调用)
- 异步执行慢操作,要么放到后台任务里,要么移出请求/响应生命周期
- 并行执行操作,而不是串行(有时为了做到这一点,会把大操作拆开)
- 用单个 SQL 查询代替一组 SQL 查询(修复 N+1 问题)
- 用快速的 SQL 查询代替慢的 SQL 查询
- 跳过不必要的慢操作(例如,在分页视图中,只从当前页上的实体获取辅助数据)

这些策略全都与语言的速度完全无关。事实上,用慢的高级语言编写,反而能让优化代码容易得多,因为你可以一眼看出程序在做什么。如果(出于某种原因)我先把 Web 服务器用汇编重写了一遍,那我就很难注意到 N+1 查询,或者我们可以把 API 调用移进后台任务这件事,等等。

结论

现在每个人都在让他们的 AI 智能体用 Rust、C 或汇编重写程序。这很有趣,但这不是认真的优化尝试。能通过这种重写获得有意义加速的程序集合非常狭窄。

如果你想用 AI 让一切更快——而且你应该想!——那你应该反过来让你的智能体对程序进行性能剖析,找出热点,并建议如何重新设计程序所做的事情。偶尔你可能会遇到一个真正是 CPU 密集型、无法通过重构来减少工作量的热点。在这些罕见的情况下,用更快的语言重写那一段会有所帮助。但只是从零开始重写,效果会远低于大多数人的想象。

用不同的语言重写软件有很多充分的理由:可移植性、效率、可维护性,等等。但就纯粹的速度而言,你最好把注意力放在程序的设计上。

---

¹ 这看起来可能高得离谱(如果你通常使用慢语言或 CPU 密集型工作负载),也可能低得离谱(如果你并非如此)。以我的经验,对于解释型语言来说,这个数字至少八九不离十。

² 这正式叫做阿姆达尔定律。

³ 为什么不直接存 HTML?你可以这样做,但有时 HTML 的内容因用户而异(即使你存了 HTML,也至少得转换一次)。

⁴ 他们声称比 tiktoken 快 4-23 倍,而在我笔记本电脑上的实测确实快了约 5 倍——不过可以说,这个加速来自重新设计以避免对 regex 的依赖,而不是因为带 Python 绑定的 Rust 本质上慢。

阅读原文
📚 相关主题 性能优化软件开发

订阅 AI Pulse

每天 08:00 · 12:30 · 18:30 · 23:50 更新