|
|
|
@ -68,7 +68,7 @@ loop {
|
|
|
|
|
|
|
|
|
|
不过,如果 Rust 真的将代码精确地编译成那样,那么每一个 `await` 都会变成阻塞操作 -- 这恰恰与我们的目标相反!相反,Rust 确保循环可以将控制权交给一些可以暂停当前 future 转而去处理其它 future 并在之后再次检查当前 future 的内容。如你所见,这就是异步运行时,这种安排和协调的工作是其主要工作之一。
|
|
|
|
|
|
|
|
|
|
在本章前面的内容中,我们描述了等待 `rx.recv`。`recv` 调用返回一个 future,并 await 轮询它的 future。我们注意到当信道关闭时运行时会暂停 future 直到它就绪并返回 `Some(message)` 或 `None` 为止。随着我们对 `Future` trait,尤其是 `Future::poll` 的理解的深入,我们可以看出其是如何工作的。运行时知道 future 返回 `Poll::Pending` 时它还没有完成。反过来说,当 `poll` 返回 `Poll::Ready(Some(message))` 或 `Poll::Ready(None)` 时运行时知道 future **已经**完成了并继续运行。
|
|
|
|
|
在本章前面的内容中,我们描述了等待 `rx.recv`。`recv` 调用返回一个 future,并 await 轮询它的 future。我们注意到运行时会暂停 future ,直到它就绪并返回 `Some(message)` ,或是信道关闭时返回 `None` 为止。随着我们对 `Future` trait,尤其是 `Future::poll` 的理解的深入,我们可以看出其是如何工作的。当返回 `Poll::Pending` 时,运行时知道 future 还没有准备就绪。反过来说,当 `poll` 返回 `Poll::Ready(Some(message))` 或 `Poll::Ready(None)` 时运行时知道 future **已经** 准备就绪,并将其推进。
|
|
|
|
|
|
|
|
|
|
运行时如何工作的具体细节超出了本书的范畴。不过关键在于理解 future 的基本机制:运行时**轮询**其所负责的每一个 future,在它们还没有完成时使其休眠。
|
|
|
|
|
|
|
|
|
@ -129,7 +129,7 @@ pub trait Future {
|
|
|
|
|
|
|
|
|
|
我们会在 [第十八章][ch-18] 更多地看到这个语法。现在,知道如果要轮询一个 future 来检查它是 `Pending` 或者 `Ready(Output)`,我们需要一个 `Pin` 封装的该类型的可变引用就够了。
|
|
|
|
|
|
|
|
|
|
`Pin` 是一个类指针类型的封装,比如 `&`,`&mut`,`Box` 和 `Rc`。(从技术上来说,`Pin` 适用于实现了 `Deref` 或 `DerefMut` trait 的类型,不过这实际上等同于只能适用于指针。)`Pin` 本身并不是一个指针并且也不具备类似 `Rc` 和 `Arc` 那样引用技术的功能;它单纯地是一个编译器可以用来约束指针使用的工具。
|
|
|
|
|
`Pin` 是一个类指针类型的封装,比如 `&`,`&mut`,`Box` 和 `Rc`。(从技术上来说,`Pin` 适用于实现了 `Deref` 或 `DerefMut` trait 的类型,不过这实际上等同于只能适用于指针。)`Pin` 本身并不是一个指针并且也不具备类似 `Rc` 和 `Arc` 那样引用计数的功能;它单纯地是一个编译器可以用来约束指针使用的工具。
|
|
|
|
|
|
|
|
|
|
回忆一下 `await` 的实现是基于对 `poll` 的调用,这有助于解释之前见到的错误信息,不过那是关于 `Unpin` 的。所以 `Pin` 具体与 `Unpin` 有何关联,又为什么 `Future` 需要 `self` 在一个 `Pin` 类型中才能调用 `poll`?
|
|
|
|
|
|
|
|
|
@ -181,7 +181,7 @@ pub trait Future {
|
|
|
|
|
|
|
|
|
|
然而,大多数类型即使被封装在 `Pin` 后面,也完全可以安全地移动。只有当项中含有内部引用的时候才需要考虑 pin。像数字或者布尔值这样的基本类型值是安全的因为很明显它们没有任何内部引用。大多数你在 Rust 中常用的类型也同样如此。例如你可以移动一个 `Vec` 而不用担心。考虑到目前我们所见到的,如果有一个 `Pin<Vec<String>>`,即便在没有其他引用的情况下 `Vec<String>` 始终可以安全移动,你仍然必须通过 `Pin` 提供的安全但有限的 API 来进行所有操作。我们需要一个方法来告诉编译器在类似这种情况下移动项是可以的 -- 这就是 `Unpin` 的用武之地了。
|
|
|
|
|
|
|
|
|
|
`Unpin` 是一个标记 trait(marker trait),类似于我们在第十六章见过的 `Send` 和 `Sync` trait,因此它们自身没有功能。标记 trait 的存在只是为了告诉编译器在给定上下文中可以安全地使用实现了给定 trait 的类型。`Unpin` 告知编译器这个给定类型**无需**维护被提及的值是否可以安全地移动的任何保证。
|
|
|
|
|
`Unpin` 是一个标记 trait(marker trait),类似于我们在第十六章见过的 `Send` 和 `Sync` trait,因此它们自身没有功能。标记 trait 的存在只是为了告诉编译器在给定上下文中可以安全地使用实现了给定 trait 的类型。`Unpin` 告知编译器这个给定类型**无需**对所涉及的值是否可以安全地移动做出任何保证。
|
|
|
|
|
|
|
|
|
|
正如 `Send` 和 `Sync` 一样,编译器自动为所有被证明为安全的类型实现 `Unpin`。同样类似于 `Send` 和 `Sync`,有一个特殊的例子**不会**为类型实现 `Unpin`。这个例子的符号是 <code>impl !Unpin for <em>SomeType</em></code>,这里 <code><em>SomeType</em></code> 指的是这样的一种类型:为了确保内存安全,当一个指向它的指针被用于 `Pin` 时,无论何时它都**必须**维护其不被移动的安全保证。
|
|
|
|
|
|
|
|
|
|