rust中的零成本抽象(zero-cost abstraction)

基本定义

C++的设计和实现者是这样定义的:

1
2
3
4
5
6
In general, C++ implementations obey the zero-overhead principle: What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.

Bjarne Stroustrup "Foundations of C++"
从整体来说,C++ 的实现遵循了零开销原则:你不需要的,无需为他们买单。更有甚者的是:你需要的时候,也不可能找到其他更好的代码了。

本贾尼·斯特劳斯特卢普 "Foundations of C++"

一般而言,构成一个零成本抽象包含以下几个要素:

  • 没有全局成本:零成本抽象不应该对不使用该功能的程序的性能产生负面影响。例如,它不能要求每个程序都携带一个沉重的语言运行时(runtime),以使唯一使用该功能的程序模块受益。
  • 最佳的性能:一个零成本的抽象应该编译成相当于底层指令编写的最佳实现。它不能引入额外的成本,而这些成本在没有抽象的情况下是可以避免的。
  • 改善开发者的体验:抽象的意义在于提供一个新的工具,由底层组件组装而成,让开发者更容易写出他们想写的代码。零成本抽象,如同所有其他抽象一样,一定要比其他方法提供更好的使用体验。

rust中零成本的抽象对象

  • 所有权和借用。当然这个是最大的一个,在没有垃圾回收器的情况下,保证内存和线程的安全,是 Rust 最初的最大的成功故事。
  • 迭代器和闭包 API。这又是一个经典之作。虽然有些情况下,内部迭代可能会优化得更好,但你可以在切片上写 map、filter、循环迭代等,它可以优化到相当于一些手写的 C 语言,这绝对是令人震惊的。
  • Async/await 和 Future。Futures API 是一个重要的例子,因为早期版本的 futures 在零成本抽象的“零成本”部分做得非常好,但实际上并没有提供足够好的用户体验来吸引用户采用。通过增加 pining 支持 async/await、跨 await 的引用等等,我们做了一个真的可以解决用户的问题的产品,让 Rust 更适合编写高性能的网络服务。
  • Unsafe 和模块边界。在所有这些,以及 Rust 的每一个成功案例的背后,都是不安全块和隐私的概念,让我们可以侵入到原始指针操作中去构建这些零成本的抽象。如果没有这种真正根本性的能力,任何一个 Rust 的辉煌成就都是不可能实现的,因为我们可以在本地环境打破规则,将系统扩展到类型检查器所能处理的范围之外。这就是零成本抽象,它是 Rust 中所有其他零成本抽象的基础。

参考资料

  • [公众号] 程序中的“零成本抽象”如何实现?