update ch17-03

This commit is contained in:
KaiserY 2024-11-05 19:32:45 +08:00
parent 60cbca60e9
commit 1e10b40423

View File

@ -247,7 +247,7 @@ received 'you'
</figure> </figure>
我们可以使用 `trpl::join!` 来 await 它们,因为它允许你传递多个 future 类型并产生一个这些类型的元组。我们 *不能* 使用 `trpl::join_all`,因为它要求传递的 future 都拥有相同的类型。请记住,那个错误正我们开启 `Pin` 探索之旅的原因! 我们可以使用 `trpl::join!` 来 await 它们,因为它允许你传递多个 future 类型并产生一个这些类型的元组。我们 *不能* 使用 `trpl::join_all`,因为它要求传递的 future 都拥有相同的类型。请记住,那个错误正我们开启 `Pin` 探索之旅的原因!
这是一个基础的权衡取舍:要么我们可以使用 `join_all` 处理动态数量的 future只要它们都有相同的类型要么我们可以使用 `join` 函数或者 `join!` 宏来处理固定数量的 future哪怕它们有着不同的类型。不过这与 Rust 处理任何其它类型是一样的。Future 并不特殊,即便我们采用了一些友好的语法来处理它们,而这其实是好事。 这是一个基础的权衡取舍:要么我们可以使用 `join_all` 处理动态数量的 future只要它们都有相同的类型要么我们可以使用 `join` 函数或者 `join!` 宏来处理固定数量的 future哪怕它们有着不同的类型。不过这与 Rust 处理任何其它类型是一样的。Future 并不特殊,即便我们采用了一些友好的语法来处理它们,而这其实是好事。
@ -271,9 +271,31 @@ received 'you'
请注意如果你反转 `race` 参数的顺序“started” 消息的顺序会改变,即使 `fast` future 总是第一个结束。这是因为这个特定的 `race` 函数实现并不是公平的。它总是以传递的参数的顺序来运行传递的 futures。其它的实现 *是* 公平的,并且会随机选择首先轮询的 future。不过无论我们使用的 race 实现是否公平,其中 *一个* future 会在另一个任务开始之前一直运行到异步代码块中第一个 `await` 为止。 请注意如果你反转 `race` 参数的顺序“started” 消息的顺序会改变,即使 `fast` future 总是第一个结束。这是因为这个特定的 `race` 函数实现并不是公平的。它总是以传递的参数的顺序来运行传递的 futures。其它的实现 *是* 公平的,并且会随机选择首先轮询的 future。不过无论我们使用的 race 实现是否公平,其中 *一个* future 会在另一个任务开始之前一直运行到异步代码块中第一个 `await` 为止。
回忆一下[第一个异步程序][async-program]中提到在每一个 await point如果被 await 的 future 还没有就绪Rust 会给运行时一个机会来暂停该任务并切换到另一个。反过来也是正确的Rust *只会* 在一个 await point 暂停异步代码块并将控制权交还给运行时。await points 之间的一切都是同步。 回忆一下[第一个异步程序][async-program]中提到在每一个 await point如果被 await 的 future 还没有就绪Rust 会给运行时一个机会来暂停该任务并切换到另一个任务。反过来也是正确的Rust *只会* 在一个 await point 暂停异步代码块并将控制权交还给运行时。await points 之间的一切都是同步。
这意味着如果你在异步代码块中做了一堆工作而没有一个 await point则那个 future 会阻塞其它任何 future 继续进行。 这意味着如果你在异步代码块中做了一堆工作而没有一个 await point则那个 future 会阻塞其它任何 future 继续进行。有时你可能会听说这称为一个 future *starving* 其它 future。在一些情况中这可能不是什么大问题。不过如果你在进行某种昂贵的设置或者上时间运行的任务亦或有一个 future 会无限持续运行某些特定任务的话,你会需要思考在何时何地将控制权交还运行时。
同样地,如果你有长时间运行的阻塞操作,异步可能是一个提供了将程序的不同部分相互关联起来的实用工具。
不过在这种情况下 *如何* 将控制权交还运行时呢?
### Yielding
让我们模拟一个长时间运行的操作。示例 17-22 引入了一个 `slow` 函数。它使用 `std::thread::sleep` 而不是 `trpl::sleep` 因此 `slow` 调用会阻塞当前线程若干毫秒。我们可以用 `slow` 来代表现实世界中的长时间运行并阻塞的操作。
<figure class="listing">
<span class="file-name">文件名src/main.rs</span>
```rust
{{#rustdoc_include ../listings/ch17-async-await/listing-17-22/src/main.rs:slow}}
```
<figcaption>示例 17-22使用 `thread::sleep` 来模拟缓慢的操作</figcaption>
</figure>
在示例 17-22 中,我们使用 `slow` 在几个 future 中模拟这类 CPU 密集型工作。首先
[collections]: ch08-01-vectors.html#using-an-enum-to-store-multiple-types [collections]: ch08-01-vectors.html#using-an-enum-to-store-multiple-types
[dyn]: ch12-03-improving-error-handling-and-modularity.html [dyn]: ch12-03-improving-error-handling-and-modularity.html