Select
Операция select ждёт, пока любой из набора фьючерсов не будет готов, и реагирует на результат этого фьючерса. В JavaScript это похоже на Promise.race. В Python аналог — asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED).
Подобно оператору match, тело select! содержит несколько ветвей, каждая в виде pattern = future => statement. Когда future готов, его возвращаемое значение деструктурируется по pattern. Затем statement выполняется с полученными переменными. Результат statement становится результатом макроса select!.
// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
use tokio::sync::mpsc;
use tokio::time::{Duration, sleep};
#[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("Hello!")).await.expect("Failed to send greeting");
listener.await.expect("Listener failed");
}
-
Асинхронный блок
listenerздесь — распространённая форма: ждать какого-нибудь асинхронного события или таймаута. Изменитеsleep, чтобы он спал дольше, и посмотрите, как всё сломается. Почему в этой ситуации тоже не удаётсяsend? -
select!также часто используется в цикле в архитектурах «акторов», где задача реагирует на события в цикле. У этого есть свои подводные камни, которые обсудим в следующем сегменте.