性能比较:循环与迭代器
要确定是否使用循环或迭代器,您需要知道哪个实现更快:search
函数的显式 for
循环版本还是迭代器版本。
我们通过将阿瑟·柯南·道尔爵士的《福尔摩斯探案集》的全部内容加载到一个String
中,并在内容中查找单词the来进行了一次基准测试。以下是使用for
循环和使用迭代器的search
版本的基准测试结果:
test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200)
这两种实现的性能相似!我们不会在这里解释基准测试代码,因为重点不是证明这两个版本是等效的,而是大致了解这两种实现的性能比较。
为了进行更全面的基准测试,你应该使用各种大小的文本作为contents
,不同的单词和不同长度的单词作为query
,以及其他各种变化。重点是:迭代器虽然是一种高级抽象,但编译后大致与你自己编写低级代码产生的代码相同。迭代器是 Rust 的零成本抽象之一,我们的意思是使用这种抽象不会增加任何额外的运行时开销。这类似于 C++ 的原始设计者和实现者 Bjarne Stroustrup 在“C++ 之基础”(2012)中定义的零开销:
通常,C++ 实现遵循零开销原则:你不用的,你就不需要为此付费。而且:你所使用的,你无法手动编写得更好。
在许多情况下,使用迭代器的 Rust 代码编译后的汇编代码与你手工编写的相同。诸如循环展开和消除数组访问的边界检查等优化措施使生成的代码极其高效。现在你已经知道这一点,可以放心地使用迭代器和闭包!它们使代码看起来像是更高层次的,但并不会因此而带来运行时性能的损失。
摘要
闭包和迭代器是受函数式编程语言思想启发的 Rust 特性。它们有助于 Rust 清晰地表达高层次的想法,同时保持低层次的性能。闭包和迭代器的实现方式不会影响运行时性能。这是 Rust 力求提供零成本抽象目标的一部分。
现在我们已经提高了 I/O 项目的表达能力,让我们来看看 cargo
的一些更多功能,这些功能将帮助我们与世界分享该项目。