Rust Async 异步编程(八):join!
Rust Async 异步编程(八):join!
招数单一,杀伤力惊人,说的就是 .await ,但是光用它,还真做不到一招鲜吃遍天。比如我们该如何同时运行多个任务,而不是使用 .await 慢悠悠地排队完成。
futures 包中提供了很多实用的工具,其中一个就是 join! 宏, 它允许我们同时等待多个不同 Future 的完成,且可以并发地运行这些 Future。
先来看一个不是很给力的、使用 .await 的版本:
async fn enjoy_book_and_music() -> (Book, Music) {
let book = enjoy_book().await;
let music = enjoy_music().await;
(book, music)
}
这段代码可以顺利运行,但是有一个很大的问题,就是必须先看完书后,才能听音乐。
要支持同时看书和听歌,有些人可能会凭空生成下面代码:
// WRONG -- 别这么做
async fn enjoy_book_and_music() -> (Book, Music) {
let book_future = enjoy_book();
let music_future = enjoy_music();
(book_future.await, music_future.await)
}
看上去像模像样,嗯,在某些语言中也许可以,但是 Rust 不行。因为在某些语言中,Future 一旦创建就开始运行,等到返回的时候,基本就可以同时结束并返回了。 但是 Rust 中的 Future 是惰性的,直到调用 .await 时,才会开始运行。而那两个 await 由于在代码中有先后顺序,因此它们是顺序运行的。
为了正确的并发运行两个 Future,我们来试试 futures::join! 宏:
use futures::join;
async fn enjoy_book_and_music() -> (Book, Music) {
let book_fut = enjoy_book();
let music_fut = enjoy_music();
join!(book_fut, music_fut)
}
这样目标就顺利达成了。同时 join! 会返回一个元组,里面的值是对应的 Future 执行结束后输出的值。
由于join!必须等待它管理的所有 Future 完成后才能完成,如果你希望在某一个 Future 报错后就立即停止所有 Future 的执行,可以使用 try_join!,特别是当 Future 返回 Result 时:
use futures::try_join;
async fn get_book() -> Result<Book, String> { /* ... */ Ok(Book) }
async fn get_music() -> Result<Music, String> { /* ... */ Ok(Music) }
async fn get_book_and_music() -> Result<(Book, Music), String> {
let book_fut = get_book();
let music_fut = get_music();
try_join!(book_fut, music_fut)
}
有一点需要注意,传给 try_join! 的所有 Future 都必须拥有相同的错误类型。如果错误类型不同,可以考虑使用来自 futures::future::TryFutureExt 模块的 map_err 和 err_info 方法将错误进行转换:
use futures::{
future::TryFutureExt,
try_join,
};
async fn get_book() -> Result<Book, ()> { /* ... */ Ok(Book) }
async fn get_music() -> Result<Music, String> { /* ... */ Ok(Music) }
async fn get_book_and_music() -> Result<(Book, Music), String> {
let book_fut = get_book().map_err(|()| "Unable to get book".to_string());
let music_fut = get_music();
try_join!(book_fut, music_fut)
}
参考:
- https://github.com/rustcn-org/async-book
- https://www.bilibili.com/video/BV1Ki4y1C7gj

被折叠的 条评论
为什么被折叠?



