rust中的零成本抽象(zero-cost abstraction)
基本定义
C++的设计和实现者是这样定义的:
1 | 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. |
一般而言,构成一个零成本抽象包含以下几个要素:
- 没有全局成本:零成本抽象不应该对不使用该功能的程序的性能产生负面影响。例如,它不能要求每个程序都携带一个沉重的语言运行时(runtime),以使唯一使用该功能的程序模块受益。
- 最佳的性能:一个零成本的抽象应该编译成相当于底层指令编写的最佳实现。它不能引入额外的成本,而这些成本在没有抽象的情况下是可以避免的。
- 改善开发者的体验:抽象的意义在于提供一个新的工具,由底层组件组装而成,让开发者更容易写出他们想写的代码。零成本抽象,如同所有其他抽象一样,一定要比其他方法提供更好的使用体验。
rust中零成本的抽象对象
- 所有权和借用。当然这个是最大的一个,在没有垃圾回收器的情况下,保证内存和线程的安全,是 Rust 最初的最大的成功故事。
- 迭代器和闭包 API。这又是一个经典之作。虽然有些情况下,内部迭代可能会优化得更好,但你可以在切片上写 map、filter、循环迭代等,它可以优化到相当于一些手写的 C 语言,这绝对是令人震惊的。
- Async/await 和 Future。Futures API 是一个重要的例子,因为早期版本的 futures 在零成本抽象的“零成本”部分做得非常好,但实际上并没有提供足够好的用户体验来吸引用户采用。通过增加 pining 支持 async/await、跨 await 的引用等等,我们做了一个真的可以解决用户的问题的产品,让 Rust 更适合编写高性能的网络服务。
- Unsafe 和模块边界。在所有这些,以及 Rust 的每一个成功案例的背后,都是不安全块和隐私的概念,让我们可以侵入到原始指针操作中去构建这些零成本的抽象。如果没有这种真正根本性的能力,任何一个 Rust 的辉煌成就都是不可能实现的,因为我们可以在本地环境打破规则,将系统扩展到类型检查器所能处理的范围之外。这就是零成本抽象,它是 Rust 中所有其他零成本抽象的基础。
参考资料
- [公众号] 程序中的“零成本抽象”如何实现?