🚧 Attention, peinture fraîche !
Cette page a été traduite par une seule personne et n'a pas été relue et vérifiée par quelqu'un d'autre ! Les informations peuvent par exemple être erronées, être formulées maladroitement, ou contenir d'autres types de fautes.
Vous pouvez contribuer à l'amélioration de cette page sur sa Pull Request.
join!
La macro futures::join
permet d'attendre que plusieurs futures différentes se
terminent pendant qu'elles sont toutes exécutées en concurrence.
join!
Lorsque nous avons besoin de faire plusieurs opérations asynchrones, il peut
être tentant d'utiliser .await
en série sur elles :
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
let livre = obtenir_livre().await;
let musique = obtenir_musique().await;
(livre, musique)
}
En revanche, cela peut être plus lent que nécessaire, puisqu'il ne commence
qu'à obtenir_musique
avant que obtenir_livre
soit terminé. Dans d'autres
langages, les futures sont exécutées normalement jusqu'à leur fin, donc deux
opérations peuvent être exécutées en concurrence en appelant chacune des
async fn
pour démarrer les futures, et ensuite attendre la fin des deux :
// MAUVAISE FAÇON -- ne faites pas cela
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
let future_livre = obtenir_livre();
let future_musique = obtenir_musique();
(future_livre.await, future_musique.await)
}
Malheureusement, les futures en Rust ne font rien tant qu'on n'utilise pas
.await
sur elles. Cela signifie que les deux extraits de code ci-dessus vont
exécuter future_livre
et future_musique
en série au lieu de les exécuter en
concurrence. Pour exécuter correctement les deux futures en concurrence,
utilisons futures::join!
:
use futures::join;
async fn obtenir_livre_et_musique() -> (Livre, Musique) {
let future_livre = obtenir_livre();
let future_musique = obtenir_musique();
join!(future_livre, future_musique)
}
La valeur retournée par join!
est une tuple contenant le résultat de chacune
des Future
s qu'on lui a donné.
try_join!
Pour les futures qui retournent Result
, il vaut mieux utiliser try_join!
plutôt que join!
. Comme join!
se termine uniquement lorsque toutes les
sous-futures se soient terminées, il va continuer à calculer les autres futures
même si une de ses sous-futures a retourné une Err
.
Contrairement à join!
, try_join!
va se terminer tout de suite si une des
sous-futures retourne une erreur.
use futures::try_join;
async fn obtenir_livre() -> Result<Livre, String> { /* ... */ Ok(Livre) }
async fn obtenir_musique() -> Result<Musique, String> { /* ... */ Ok(Musique) }
async fn obtenir_livre_et_musique() -> Result<(Livre, Musique), String> {
let future_livre = obtenir_livre();
let future_musique = obtenir_musique();
try_join!(future_livre, future_musique)
}
Notez que les futures envoyées au try_join!
doivent toutes avoir le même type
d'erreur. Vous pouvez utiliser les fonctions .map_err(|e| ...)
et
.err_into()
de futures::future::TryFutureExt
pour regrouper les types
d'erreurs :
use futures::{
future::TryFutureExt,
try_join,
};
async fn obtenir_livre() -> Result<Livre, ()> { /* ... */ Ok(Livre) }
async fn obtenir_musique() -> Result<Musique, String> { /* ... */ Ok(Musique) }
async fn obtenir_livre_et_musique() -> Result<(Livre, Musique), String> {
let future_livre = obtenir_livre().map_err(|()| "Impossible d'obtenir le livre".to_string());
let future_musique = obtenir_musique();
try_join!(future_livre, future_musique)
}