17611538698
webmaster@21cto.com

软件运行缓慢是因为设计糟糕,而不是因为编程语言本身慢

架构 0 19 1小时前
图片

21CTO导读:最近有不少软件将原语言通过AI重写为Rust版本,但这种做法是正确的吗?

许多人认为人工智能可以通过使用更快的编程语言重写软件,从而来提高软件运行速度,但这通常并不是正确的。

大多数程序即使使用 C 或 Rust 重写也无法显著提升运行速度。

这种解释为何是正确的呢?

有些语言的速度比其他语言快几个数量级:例如,C 语言的速度大概是Python 的五十倍。那么,如果我用 C 语言重写我的 Python 程序,它的速度岂不是也会提高五十倍吗?然而并非如此。软件性能通常取决于 I/O 操作,而不是语言本身的速度。在语言速度至关重要的情况下,大多数速度较慢的语言都已经拥有流行的库,可以帮助它们达到类似 C 语言的速度。

因此总体来说,性能取决于设计,而不是语言的选择。

实际上我们大多数程序都是 I/O 密集型的。

来思考一个带有数据库的 CRUD 型网站。对于任何给定的请求,50% 的请求时间可能都花在了查询数据库上。比如获取当前用户、请求的订阅记录、任何相关的用户成员关系或设置等等。用 C 语言重写该网站只提升 50% 的查询速度,这限制了你能实现的改进幅度。

最好的情况是,请求速度提升一倍。

换句话说,大多数程序实际都是“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,速度提升了4倍。

然而,你不可能通过这种方式彻底改变某个计算领域。即使是快速的词法分析也只能起到辅助作用,因为词法分析所花费的时间只是推理所花费时间的一小部分。

提高软件运行速度通常情况下需要重新设计。

尽管如此,我认为大多数软件的运行速度仍然远低于其应有的水平。我对常用软件(无论是否借助人工智能)大幅提升运行速度的潜力持乐观态度。但我认为,这些速度提升主要来自于程序的重新设计,而不是用更快的语言重写。

在 2018 年的一篇文章中,Bryan Cantrill 描述了他尝试将一个 C 程序重写为 Rust 的经历。这段旅程非常困难,因为 C 程序经过精心优化的设计与 Rust 的借用检查器并不兼容。他最终放弃了,直接用 Rust 以最简单的方式重写了程序,预期速度至少会降低 20%。

然而,结果却提升了 30% 。原因在于 Rust 内部更倾向于使用 B 树而不是二叉搜索树,而 B 树恰好是一种缓存效率更高的数据结构。因此,即使在 CPU 密集型工作负载中,对于一位精通 C 语言编程的开发者来说,性能也主要取决于设计,而非语言本身的速度。

这与我使用高级语言的经验相符。回想我所取得的显著速度提升,几乎都是通过重新设计软件来减少工作量实现的:

缓存慢速操作(通常是外部 API 调用)

异步执行慢速操作,无论是在后台作业中还是在请求/响应生命周期之外,并行执行操作而不是顺序执行操作(有时为了实现这一点,需要将大型操作拆分成多个步骤),例如用单个 SQL 查询替换一组 SQL 查询(解决N+1问题)。

用快速 SQL 查询替换慢速 SQL 查询跳过不必要的慢速操作(例如,在分页视图中,仅从当前页面上的实体获取辅助数据)。

所有这些策略都与语言的运行速度完全无关。

事实上,使用速度较慢的高级语言编写代码反而更容易优化,因为你可以一目了然地了解程序的运行机制。如果(出于某种原因)我一开始就用汇编语言重写了 Web 服务器,那么我就很难注意到 N+1 查询,或者意识到我们可以将 API 调用移到一个作业中等等。

结语

现在大家都在要求人工智能代理用 Rust、C 或汇编语言重写程序。这固然有趣,但并非真正意义上的优化。能够通过这种重写方式显著提升速度的程序范围非常有限。

如果你想利用人工智能提升一切速度——而你也应该这么做!——你应该让你的智能体分析程序,识别瓶颈,并提出重新设计程序功能的建议。有时你可能会遇到真正受 CPU 限制的瓶颈,无法通过重构来减少工作量。在这些罕见的情况下,用更快的语言重写该部分代码会有所帮助。但简单地从头开始重写代码的效果远不如大多数人想象的那样好。

用不同的语言重写软件有很多的好处,包括可移植性、效率、可维护性等等。但就纯粹的运行速度而言,我们还是把精力放在程序的设计上为佳。

作者:洛逸

参考:

https://www.seangoedecke.com/software-is-slow-because-of-bad-design-not-slow-languages

评论

我要赞赏作者

请扫描二维码,使用微信支付哦。

分享到微信