Select

Операція select очікує, поки будь-який із набору ф’ючерсів буде готовий, і відповідає на результат цього ф’ючерсу. У JavaScript це схоже на Promise.race. У Python це порівнюється з asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED).

Подібно до оператора порівняння, тіло select! має кілька гілок, кожен з яких має вигляд 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!("отримав: {msg}"),
            _ = sleep(Duration::from_millis(50)) => println!("тайм-аут"),
        };
    });
    sleep(Duration::from_millis(10)).await;
    tx.send(String::from("Привіт!")).await.expect("Не вдалося надіслати привітання.");

    listener.await.expect("Listener зазнав невдачі");
}
This slide should take about 5 minutes.
  • Блок асинхронізації listener тут є звичайною формою: очікування деякої асинхронної події або таймауту. Змініть sleep на довший час, щоб побачити, що він не спрацює. Чому в цій ситуації також не спрацьовує send?

  • Команда select! також часто використовується у циклі в "actor" архітектурах, де завдання реагує на події у циклі. Це має деякі підводні камені, які буде обговорено у наступному розділі.