Skip to content

Latest commit

 

History

History
80 lines (56 loc) · 2.46 KB

6-1-join!.md

File metadata and controls

80 lines (56 loc) · 2.46 KB

futures::join宏并发地执行不同的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。在一些其他语言,futures几乎可以完全运行,因此两个操作可以通过首先调用每个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的futuresawait之前不会做任何工作。这就意味着上面的两个代码片段串行地执行book_futuremusic_future而不是并行。为了正确地并行运行两个futures,使用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完成了才算完成,即使子futures返回一个Err,它也会继续执行其他子future

join!不同,如果有一个子future完成,try_join!会立马完成。

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必须有相同的error类型。考虑使用futures::future::TryFutureExt中的.map_err(|e| ...).err_into函数来统一error类型。

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)
}