纯函数式编程可以接近C的程度有多近?
2026年10月22日 在《为什么Lean比Rust更快》中,作者分享了一个令人印象深刻的结果:一个用Lean 4编写的DEFLATE压缩库,这是一种函数式编程语言及证明助手,其性能超过了一个Rust包,而该Rust包在crates.io上已被下载超过十亿次。文章中提到:lean-zip在每一个miniz_oxide提供的压缩级别上都优于,即我们能够以更高的吞吐量提供相同的压缩。在其最快的设置下,我们比之快15%,输出也小了8.8%。然而,文章还指出,虽然他们成功超越了Rust的miniz_oxide,但在DEFLATE性能的最终Boss——用C编写的libdeflate面前,他们依然不敌。lean-zip在这里显然不是最佳的:libdeflate毫不意外地把它甩得远远的(这毫不意外,因为这是一个非常精心调整的实现,使用了特定于架构的SIMD,而我们在Lean中无法触及)。引入Roc,这是一种函数式编程语言(但不是定理证明器),明确关注运行时性能。Roc的标语是“快速、友好、函数式”,其中“快速”排在第一位,因为快速运行和快速编译始终是中心目标。Roc不是一种成熟的语言(离其第一个编号发行版0.1.0还有几周),而其初步的包生态系统几乎没有进行过优化工作。尽管如此,在其语言设计、长期优化及全新的编译器实现之间,我认为Roc已经具备了足够的基础去挑战冠军:libdeflate。因此,我花了大量时间在roc-deflate(Niclas Ahden编写并用于付费生产工作的DEFLATE压缩包)上进行性能优化。我并不期望在所有方面都超过libdeflate的性能,但我想看看它在非流式API上能接近多远(因为roc-deflate还没有实现流式),使用经典的Silesia语料库进行基准测试,并验证它生成的输出是否相同。慢10%以下 今天基准测试的结果如下,在我进行所有优化工作的2021 M1 MacBook Pro上运行,以及在AMD Ryzen 9 3900X Ubuntu机器上的x64比较。roc-deflate的这144个基准测试的平均运行速度比libdeflate慢,在中位数情况下在Ryzen 3900X上慢了8.9%,在M1 MacBook Pro上慢了2.6%。 Silesia语料库上的压缩 M1 MacBook Pro Ryzen 3900X Ubuntu MB/s L1 L2 L3 L4 L5 L6 L7 L8 L9 L10 L11 L12 libdeflate roc-deflate 压缩级别 MB/s L1 L2 L3 L4 L5 L6 L7 L8 L9 L10 L11 L12 libdeflate roc-deflate 压缩级别 所以尽管我们没有在平均水平上超越冠军,但与如此精心调优的基于SIMD的C库相比,中位数的减速百分比仅为个位数,这实在是不可思议。坦率地说,这不是我在进去时就预料到的结果,因为Roc是一种具有自动内存管理的函数式语言,正与不需要进行边界检查的代码竞争。(边界检查是有成本的,但再说一次,上次在C压缩代码中跳过边界检查导致重大远程代码执行漏洞是在昨天。)图表显示的信息不仅是中位数差距。在最坏情况下,roc-deflate比libdeflate慢18%,但在最佳情况下,roc-deflate快了稍微超过18%!这并不是因为Roc有某种C无法访问的神奇优化;而是这两个实现不同,尽管平均而言roc-deflate较慢,但对于某些输入,它碰巧更快。因此,尽管通过从libdeflate切换到roc-deflate可以获得速度提升,但你不应该期待这种提升出现在平均水平上。明确一点,C的性能上限高于Roc的。在当前roc-deflate超越libdeflate的任何输入上,C代码能够缩小这一差距。相反则不然;Roc代码是内存安全的,支持自动引用计数,检查边界,并且没有Rust风格的不安全选项来“跳过”这些。 这些属性使得Roc代码比用C、Zig、Rust以及其他允许完全访问硬件的语言编写的代码具有更强的安全保障,而为这些保障所付出的代价便是更低的性能上限。显然,我们不能从这个单一结果推断Roc在一般情况下能接近C的程度,但现在已经展示了一些之前没人知道可以实现的东西。就我所知,这是迄今为止投入到任何Roc包的最大优化努力,因此其他人能接近这个结果的程度目前完全未知。尽管对这个结果感到兴奋,我完全意识到,在我们优化了更广泛的真实Roc代码库之前,我们不会知道其广泛性如何! 性能差距带来了什么 一个显而易见的问题是“为什么要满足于任何程度的慢?”如果你可以获得C级别的性能,为什么不直接使用libdeflate并弥补剩余的差距?
阅读全文 →本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡