mirror of
https://github.com/gnu4cn/rust-lang-zh_CN.git
synced 2025-01-30 06:00:13 +08:00
Reviewed Ch13
This commit is contained in:
parent
864d704422
commit
d1407d406c
@ -983,7 +983,7 @@ test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200)
|
||||
|
||||
> 一般来说,C++ 的实现遵循零开销原则:咱们不使用的东西,咱们不需要付出开销。再进一步:咱们使用的东西,咱们不可能手写出更良好的代码,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。
|
||||
|
||||
作为另一个示例,以下代码取自某个音频解码器。解码算法使用线性预测的数学运算,根据之前样本的线性函数来估计后面的数值。此代码使用迭代器链,an iterator chain=,对作用域中三个变量执行一些计算:由一些数据构成 `buffer` 切片,由 12 个 `coeffecients` 构成的一个数组,以及其中保存着数据偏移量的 `qlp_shift`。咱们已在这个示例中声明了变量,但并未给他们任何值;尽管此代码在其上下文之外没有什么意义,但他仍不失为说明 Rust 如何将高级别的概念,转化低级别代码的一个简练、真实的示例。
|
||||
作为另一个示例,以下代码取自某个音频解码器。解码算法使用线性预测的数学运算,根据之前样本的线性函数来估计后面的数值。此代码使用迭代器链,an iterator chain,对作用域中三个变量执行一些数学计算:由一些数据构成 `buffer` 切片,由 12 个 `coeffecients` 构成的一个数组,以及保存着数据偏移量的 `qlp_shift`。咱们已在这个示例中声明了变量,但并未给他们任何值;尽管此代码在其上下文之外没有什么意义,但他仍不失为说明 Rust 如何将高级别的概念,转化为低级别代码的一个简练、真实的示例。
|
||||
|
||||
```rust
|
||||
let buffer: &mut [i32];
|
||||
@ -1000,16 +1000,16 @@ for i in 12..buffer.len() {
|
||||
}
|
||||
```
|
||||
|
||||
为了计算出 `prediction` 的值,此代码对 `coefficients` 中 12 个值的每个都进行了迭代,并使用 `zip` 方法将这些系数值与 `buffer` 中的前 12 个值配对起来。随后对这个每个数值对,这里将他们放一起做乘法,对这些结果求和,并将和数中的那些二进制位,往右偏移了 `qlp_shift` 个二进制位。
|
||||
为了计算预测值,此代码遍历 `coefficients` 中 12 个值中的每一个,并使用 `zip` 方法将系数值与 `buffer` 中的前 12 个值配对。随后对每个数值对,咱们将数值相乘,对所有结果求和,并将总和中的二进制位,向右偏移 `qlp_shift` 位。
|
||||
|
||||
像是音频解码器这样得应用中的那些计算,通常要将性能放在最高的优先级。这里,就创建出了一个迭代器,使用了两个适配器,并在随后消费了那个值。而这段代码会编译到什么样的汇编代码呢?当然,在这本书编写时,他会向下编译到由手写的同样汇编代码。注意相应于对 `coefficients` 中那些值的迭代,是完全没有循环的:Rust 清楚那里有 12 次迭代,因此他(Rust 编译器)就会 “解开(unrolls)” 其中那个循环。所谓 “解开(unrolling)”,是消除循环控制代码方面的开销,而以生成该循环历次迭代的重复代码予以取代的一种优化(*unrolling* is an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration of the loop)。
|
||||
像是音频解码器这样的应用中的计算,通常最优先考虑的是性能。在这里,我们正在创建一个迭代器,使用两个适配器,然后消费这个值。这段 Rust 代码会编译成什么汇编代码呢?好吧,在写这篇文章时,他可以编译成与咱们用手写的相同汇编代码。在系数的迭代过程中完全没有对应的循环: Rust 知道有 12 个迭代,所以他 “展开” 了这个循环。所谓 “展开,unrolling”,是消除循环控制代码方面的开销,而代之以生成循环历次迭代的重复代码的一种优化,*unrolling* is an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration of the loop。
|
||||
|
||||
全部的这些系数,都是被存储在寄存器中的,这意味着访问这些值是极为快速的。运行时是没有数组上的边界检查的。这些 Rust 所能运用的全部优化,就令到最终代码极为高效。既然现在获悉到这一点,那么就可以毫无顾忌的使用迭代器和闭包了!他们使得代码看起来像是在较高的层级,但这样做并不会造成运行时性能下降。
|
||||
所有的系数都被存储在寄存器中,这意味着访问这些值的速度非常快。在运行时,对数组的访问没有边界检查。Rust 能够应用的所有这些优化使得所产生的代码非常高效。现在咱们知道了这些,咱们就可以毫无顾忌地使用迭代器和闭包了!他们使代码看起来更高级,但不会因为这样做而带来运行时的性能损失。
|
||||
|
||||
|
||||
|
||||
## 本章小结
|
||||
|
||||
闭包与迭代器,是 Rust 的两项受函数式编程概念启发的特性。他们带来了 Rust 的有着底层代码性能、但以高级语言清晰表达概念的能力。闭包与迭代器的实现,不会影响到运行时性能。这正是 Rust 致力于提供到无代价抽象(zero-cost abstractions),这一目标的一个方面。
|
||||
闭包与迭代器,是 Rust 受函数式编程概念启发的两项特性。他们有助于 Rust 以底层性能清楚表达高级别概念的能力。闭包与迭代器的实现,不会影响到运行时性能。这正是 Rust 致力于提供零成本抽象目标的一部分。
|
||||
|
||||
既然现在已经改进了这个 I/O 项目的表现力,那么接下来就要看看,`cargo` 的一些别的、将帮助咱们与外界分享这个项目的一些特性了。
|
||||
现在我们已经改进了 I/O 项目的表达能力,让我们再来看看 `cargo` 的一些特性,这些特性将帮助我们与世界分享这个项目。
|
||||
|
@ -805,10 +805,17 @@ Consuming adaptor, `Iterator` 特质上,会调用到迭代器 `next` 方法的
|
||||
|
||||
Iterator adaptor,`Iterator` 特质上,通过改变原迭代器某些方面而产生出另一迭代器的一些方法。
|
||||
|
||||
|
||||
- 零成本抽象
|
||||
|
||||
Zero-cost abstractions,相较于一般实现,语言提供的高级抽象在编译后生成的代码,与自己努力编写出的优化低级别代码类似。故使用高级抽象是没有运行时开销的。
|
||||
|
||||
|
||||
- 展开优化
|
||||
|
||||
Unrolling,Rust 编译器在编译迭代器代码时,会把已知的历次迭代展开为重复代码,而实现性能优化。
|
||||
|
||||
|
||||
- 文档注释
|
||||
|
||||
Documentation comment, 将产生出 HTML 的注释。
|
||||
|
Loading…
Reference in New Issue
Block a user