diff --git a/src/ch17-02-concurrency-with-async.md b/src/ch17-02-concurrency-with-async.md index ff90aa033..12a6bd523 100644 --- a/src/ch17-02-concurrency-with-async.md +++ b/src/ch17-02-concurrency-with-async.md @@ -133,3 +133,43 @@ hi number 9 from the first task! - 直将第一个循环封装进异步代码块,并在第二个循环体之后 await 作为结果的 future。 作为额外的挑战,看看你能否在运行代码 *之前* 想出每个情况下的输出! + +### 消息传递 + +在 future 之间共享数据也与线程类似:我们会再次使用消息传递,不过会使用异步版本的类型和函数。我们会采用与之前第十六章中使用的稍微不同的方法,来展示一些基于线程的并发与基于 future 的并发之间的关键不同。在示例 17-9 中,我们会从仅有一个异步代码块开始,*不像* 产生独立线程那样产生一个独立的任务。 + +
+ +文件名:src/main.rs + +```rust +{{#rustdoc_include ../listings/ch17-async-await/listing-17-09/src/main.rs:channel}} +``` + +
示例 17-9:创建一个异步信道(async channel)并赋值其两端为 `tx` 和 `rx`
+ +
+ +这里我们使用了 `trpl::channel`,一个第十六章用于现场的多生产者、单消费者信道 API 的异步版本。异步版本的 API 与基于线程的版本只有一点微小的区别:它使用一个可变的而不是不可变的 `rx`,并且它的 `recv` 方法产生一个需要 await 的 future 而不是直接返回值。现在我们可以发送端向接收端发送消息了。注意我们无需产生一个独立的线程或者任务;只需等待(await) `rx.recv` 调用。 + +`std::mpsc::channel` 中的同步 `Receiver::recv` 方法阻塞执行直到它接收一个消息。`trpl::Receiver::recv` 则不会阻塞,因为它是异步的。不同于阻塞,它将控制权交还给运行时直到接收到一个消息或者信道的发送端关闭。与此相对,我们不用 await `send`,因为它不阻塞。它也不需要,因为信道的发送端的数量是没有限制的。 + +> 注意:因为所有这些异步代码都运行在一个 `trpl::run` 调用的异步代码块中,其中的所有代码可以避免阻塞。然而,*外面* 的代码会阻塞到 `run` 函数返回。这是 `trpl::run` 函数的全部意义:它允许你 *选择* 在何处阻塞一部分异步代码,也就是在何处进行同步和异步代码的转换。这正是在大部分运行时中 `run` 实际上被命名为 `block_on` 的原因。 + +注意这个示例中的两个地方:首先,消息立刻就会到达!第二,虽然我们使用了 future,但是这里还没有并发。示例中的所有事情都是顺序发生的,就像没涉及到 future 时一样。 + +让我们通过发送一系列消息并在之间休眠来解决第一个问题,如示例 17-10 所示: + +
+ +文件名:src/main.rs + +```rust +{{#rustdoc_include ../listings/ch17-async-await/listing-17-09/src/main.rs:channel}} +``` + +
示例 17-10:通过异步信道发送和接收多个消息并在每个消息之间通过 `await` 休眠
+ +
+ +除了发送消息之外,我们需要接收它们。