Select

select 操作は、複数の future のうちいずれか 1 つの準備ができるまで待機し、その future の結果に応じて処理を行います。JavaScript では、これは Promise.race に 似ています。Python では、 asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED) に相当します。

match 文と同様に、select! の本体には複数のアームがあり、それぞれ pattern = future => statement という形式を取ります。future の準備ができると、 その戻り値は pattern によって分解されます。続いて、得られた変数を使って statement が実行されます。statement の結果が select! マクロの結果になります。

// 著作権 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 async ブロックは一般的な形です。何らかの async イベント、 またはタイムアウトを待ちます。sleep をより長くして、失敗することを確認して ください。この状況で send も失敗するのはなぜでしょうか?

  • 「アクター」アーキテクチャでは、select! はループ内でもよく使われます。そこでは タスクがループ内でイベントに反応します。これにはいくつかの落とし穴があり、 それについては次のセグメントで説明します。