Select
Uma operação de select espera até que qualquer uma das futures de um conjunto esteja pronta e responde ao resultado dessa future. Em JavaScript, isso é semelhante a Promise.race
. Em Python, compara-se a asyncio.wait(task_set, return_when=asyncio.FIRST_COMPLETED)
.
Semelhante a uma instrução match, o corpo de select!
tem um número de ramos, cada um da forma pattern = future => statement
. Quando um future
está pronto, seu valor de retorno é desestruturado pelo pattern
. O statement
é então executado com as variáveis resultantes. O resultado do statement
se torna o resultado da macro select!
.
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("Falha ao enviar gato."); }); tokio::spawn(async move { sleep(Duration::from_millis(50)).await; dog_sender.send(String::from("Rex")).await.expect("Falha ao enviar cachorro."); }); let winner = first_animal_to_finish_race(cat_receiver, dog_receiver) .await .expect("Falha ao receber vencedor"); println!("O vencedor é {winner:?}"); }
-
Neste exemplo, temos uma corrida entre um gato e um cachorro.
first_animal_to_finish_race
escuta ambos os canais e escolherá o que chegar primeiro. Como o cachorro leva 50ms, ele vence contra o gato que leva 500ms. -
Você pode usar canais
oneshot
neste exemplo, já que os canais devem receber apenas umsend
. -
Tente adicionar um prazo para a corrida, demonstrando a seleção de diferentes tipos de futures.
-
Observe que
select!
descarta ramos não correspondidos, o que cancela suas futures. É mais fácil de usar quando cada execução deselect!
cria novas futures.- Uma alternativa é passar
&mut future
em vez da própria future, mas isso pode levar a problemas, discutidos mais adiante no slide de pinning.
- Uma alternativa é passar