async
/.await
Primer
async
/.await
是 Rust 的内置工具,用于编写看起来像同步代码的异步函数。async
将一个代码区块,转换为实现称为 Future
trait 的状态机。而在同步方法中,调用阻塞函数将阻塞整个线程,Future
s 将 yield 对线程的控制权,允许其他Future
运行。
要创建异步功能,您可以使用async fn
语法:
#![allow(unused_variables)] fn main() { async fn do_something() { ... } }
async fn
传回的值,是一个Future
。对要发生事情的衡量,Future
需要在一个 executor 上运行。
// `block_on` blocks the current thread until the provided future has run to // completion. Other executors provide more complex behavior, like scheduling // multiple futures onto the same thread. use futures::executor::block_on; async fn hello_world() { println!("hello, world!"); } fn main() { let future = hello_world(); // Nothing is printed block_on(future); // `future` is run and "hello, world!" is printed }
在async fn
内部, 您可以使用.await
,等待另一种实现Future
trait 的类型完成它的操作,例如另一个async fn
的输出。不像block_on
,.await
不会阻塞当前线程,而是异步等待 future 完成。这样的话,如果 future 当前无法取得进展,则允许其他任务运行。
例如,假设我们有三个async fn
:learn_song
,sing_song
和dance
:
#![allow(unused_variables)] fn main() { async fn learn_song() -> Song { ... } async fn sing_song(song: Song) { ... } async fn dance() { ... } }
选择学习(learn_song),唱歌(sing_song)和跳舞(dance)的任一种,都会分别阻塞每个人:
fn main() { let song = block_on(learn_song()); block_on(sing_song(song)); block_on(dance()); }
但是,我们并没有达到这异步形式的最佳性能 —— 我们一次只能做一件事情!显然,我们必须先学习这首歌,然后才能唱歌,但是可以在学习和唱歌的同时跳舞。为此,我们可以创建两个单独的async fn
,而它们可以同时运行:
async fn learn_and_sing() { // Wait until the song has been learned before singing it. // We use `.await` here rather than `block_on` to prevent blocking the // thread, which makes it possible to `dance` at the same time. let song = learn_song().await; sing_song(song).await; } async fn async_main() { let f1 = learn_and_sing(); let f2 = dance(); // `join!` is like `.await` but can wait for multiple futures concurrently. // If we're temporarily blocked in the `learn_and_sing` future, the `dance` // future will take over the current thread. If `dance` becomes blocked, // `learn_and_sing` can take back over. If both futures are blocked, then // `async_main` is blocked and will yield to the executor. futures::join!(f1, f2); } fn main() { block_on(async_main()); }
在此示例中,学习歌曲必须在唱歌之前发生,但是学习和唱歌都可以与跳舞同时发生。如果在learn_and_sing
,我们使用block_on(learn_song())
,而不是learn_song().await
,那只要learn_song
正在运行,该线程就无法执行其他任何操作。这样就不可能同时跳舞。通过对 learn_song
future 使用.await
,那么如果learn_song
被阻塞,就允许其他任务接管当前线程。这样就可以在同一线程上,同时运行多个 futures。
现在,您已经了解了async
/await
的基础知识,让我们尝试一个例子。