join!
优质
小牛编辑
148浏览
2023-12-01
futures::join
宏的魔力在于,同时执行 Futures 时,等待多个不同的 Futures 完成。
join!
当执行多个异步操作时,一串.await
,就搞定他们:
async fn get_book_and_music() -> (Book, Music) {
let book = get_book().await;
let music = get_music().await;
(book, music)
}
但是,这还是比所要的速度慢,因为它不会在get_book
已经完成之后,开始尝试get_music
。在其他一些语言中, Future 是环境运行到完成,因此可以,先调用每个async fn
,来开始 futures,这样两个操作就是同时运行的,然后就是等待两个:
// WRONG -- don't do this
async fn get_book_and_music() -> (Book, Music) {
let book_future = get_book();
let music_future = get_music();
(book_future.await, music_future.await)
}
但是,Rust Futures 在处于.await
ed 之前不会做任何工作。这意味着,上面的两个代码片段,都将连续运行book_future
和music_future
,而不是同时运行它们。要同时正确运行两个 Future ,请使用futures::join!
:
use futures::join;
async fn get_book_and_music() -> (Book, Music) {
let book_fut = get_book();
let music_fut = get_music();
join!(book_fut, music_fut)
}
join!
传回的值,是一个元组,包含每个传递进去的Future
的输出。
try_join!
要想 Futures 返回的是 Result
,请考虑使用try_join!
而不是join!
。只因join!
仅在所有子 Future 都完成后,才完成,即便是它的其中一个 subfutures 是返回了一个Err
。
不像join!
,在try_join!
中,如果其中一个 subfutures 返回一个错误,将立即完成。
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!
的 Futures 必须都具有相同的错误类型。考虑使用futures::future::TryFutureExt
中的.map_err(|e| ...)
和.err_into()
函数,来合并错误类型:
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)
}