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_raceescuta 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
oneshotneste 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 futureem vez da própria future, mas isso pode levar a problemas, discutidos mais adiante no slide de pinning.
- Uma alternativa é passar