Select

یک عملیات انتخابی منتظر می‌ماند تا هر یک از مجموعه‌ای از futureها آماده شود و به نتیجه آن future پاسخ می‌دهد. در JavaScript این مورد شبیه به Promise.race است و در پایتون با asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED) قابل مقایسه می‌باشد.

مانند یک عبارت تطبیقی (match statement)، بدنه pattern دارای تعدادی بازو است که هر کدام به شکل عبارت pattern = future => statement هستند. هنگامی که future آماده است، مقدار بازگشتی آن توسط pattern تخریب می‌شود. سپس statement با متغیرهای حاصل اجرا می‌شود. در نتیجه statement نتیجه‌ي ماکرو select! می‌شود.

use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);
    let listener = tokio::spawn(async move {
        tokio::select! {
            Some(msg) = rx.recv() => println!("got: {msg}"),
            _ = sleep(Duration::from_millis(50)) => println!("timeout"),
        };
    });
    sleep(Duration::from_millis(10)).await;
    tx.send(String::from("سلام!")).await.expect("Failed to send greeting");

    listener.await.expect("شنونده شکست خورد");
}
This slide should take about 5 minutes.
  • بلوک async listener در اینجا یک شکل رایج است: منتظر برخی رویدادهای async یا به‌عنوان مثال برای timeoutها باشید. sleep را به sleep طولانی‌تر تغییر دهید تا شاهد شکست آن باشید. چرا send نیز در این شرایط شکست می‌خورد؟

  • select! is also often used in a loop in "actor" architectures, where a task reacts to events in a loop. That has some pitfalls, which will be discussed in the next segment.