Reviewed Ch13

This commit is contained in:
Peng Hailin, 2023-05-04 20:21:17 +08:00
parent 864d704422
commit d1407d406c
2 changed files with 13 additions and 6 deletions

View File

@ -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` 的一些特性,这些特性将帮助我们与世界分享这个项目

View File

@ -805,10 +805,17 @@ Consuming adaptor, `Iterator` 特质上,会调用到迭代器 `next` 方法的
Iterator adaptor`Iterator` 特质上,通过改变原迭代器某些方面而产生出另一迭代器的一些方法。
- 零成本抽象
Zero-cost abstractions相较于一般实现语言提供的高级抽象在编译后生成的代码与自己努力编写出的优化低级别代码类似。故使用高级抽象是没有运行时开销的。
- 展开优化
UnrollingRust 编译器在编译迭代器代码时,会把已知的历次迭代展开为重复代码,而实现性能优化。
- 文档注释
Documentation comment, 将产生出 HTML 的注释。