Join

عملیات پیوستن (join) منتظر می‌ماند تا تمام مجموعه‌ای از futureها آماده شوند و مجموعه‌ای (collection) از نتایج آنها را برمی‌گرداند. این شبیه به Promise.all در JavaScript یا asyncio.gather در پایتون است.

use anyhow::Result;
use futures::future;
use reqwest;
use std::collections::HashMap;

async fn size_of_page(url: &str) -> Result<usize> {
    let resp = reqwest::get(url).await?;
    Ok(resp.text().await?.len())
}

#[tokio::main]
async fn main() {
    let urls: [&str; 4] = [
        "https://google.com",
        "https://httpbin.org/ip",
        "https://play.rust-lang.org/",
        "BAD_URL",
    ];
    let futures_iter = urls.into_iter().map(size_of_page);
    let results = future::join_all(futures_iter).await;
    let page_sizes_dict: HashMap<&str, Result<usize>> =
        urls.into_iter().zip(results.into_iter()).collect();
    println!("{:?}", page_sizes_dict);
}
This slide should take about 4 minutes.

این مثال را در src/main.rs آماده شده خود کپی کنید و آن را از آنجا اجرا کنید.

  • برای چند future از تایپ‌های مختلف، می‌توانید از std::future::join! استفاده کنید، اما باید بدانید که در زمان کامپایل چند future خواهید داشت. این در حال حاضر در جعبه (crate از نوع futures است که به زودی در std::future تثبیت می‌شود.

  • خطر join این است که یکی از future‌ها ممکن است هرگز resolve نشود، این مسئله باعث می‌شود برنامه شما متوقف شود.

  • همچنین می‌توانید join_all را با join! ترکیب کنید، به‌عنوان مثال برای پیوستن (join!) همه درخواست‌ها به یک سرویس http و همچنین یک کوئری پایگاه داده سعی کنید tokio::time::sleep را با استفاده از futures::join! به future اضافه کنید. این یک timeout نیست (که به select!نیاز دارد و در فصل بعدی توضیح داده ‌می‌شود) بلکه join! را نشان می‌دهد.