Select
Selectという操作では、futureの集合のうち、いずれか1つの準備が整うまで待機し、そのfutureが提供する結果に対して応答します。これはJavaScriptにおけるPromise.race
に似ています。また、Pythonにおける asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED)
と比べることができます。
Similar to a match statement, the body of select!
has a number of arms, each of the form pattern = future => statement
. When a future
is ready, its return value is destructured by the pattern
. The statement
is then run with the resulting variables. The statement
result becomes the result of the select!
macro.
use tokio::sync::mpsc::{self, Receiver}; use tokio::time::{sleep, Duration}; #[derive(Debug, PartialEq)] enum Animal { Cat { name: String }, Dog { name: String }, } async fn first_animal_to_finish_race( mut cat_rcv: Receiver<String>, mut dog_rcv: Receiver<String>, ) -> Option<Animal> { tokio::select! { cat_name = cat_rcv.recv() => Some(Animal::Cat { name: cat_name? }), dog_name = dog_rcv.recv() => Some(Animal::Dog { name: dog_name? }) } } #[tokio::main] async fn main() { let (cat_sender, cat_receiver) = mpsc::channel(32); let (dog_sender, dog_receiver) = mpsc::channel(32); tokio::spawn(async move { sleep(Duration::from_millis(500)).await; cat_sender.send(String::from("Felix")).await.expect("Failed to send cat."); }); tokio::spawn(async move { sleep(Duration::from_millis(50)).await; dog_sender.send(String::from("Rex")).await.expect("Failed to send dog."); }); let winner = first_animal_to_finish_race(cat_receiver, dog_receiver) .await .expect("Failed to receive winner"); println!("Winner is {winner:?}"); }
-
In this example, we have a race between a cat and a dog.
first_animal_to_finish_race
listens to both channels and will pick whichever arrives first. Since the dog takes 50ms, it wins against the cat that take 500ms. -
この例では
oneshot
チャネルを使うこともできます。なぜなら、チャネルは一回きりのsend
を受け取ることになっているからです。 -
レースに制限時間を追加することによって、違う種類のfutureをselectすることを実演してみてください。
-
select!
はマッチしなかったブランチをドロップすることに注意してください。これは、そうしたブランチのfutureがキャンセルされることにつながります。select!
を毎回実行する際に新たなfutureが作成されるときに、select!
を使うのが最も簡単です。- Futureそのものでなく、
&mut future
を渡すという代替案もあります。しかし、これは問題につながることもあります。このことはPinに関するスライドで詳細に議論します。
- Futureそのものでなく、