Comment exécuter plusieurs fonctions asynchrones à la fois et obtenir les résultats ?

Aug 18 2020

J'ai essayé les tâches Tokio, mais il n'y a pas d'exemples de travail pour exécuter plusieurs tâches à la fois. Quel est le problème avec ce code ?

fn main() {
    block_on(speak());
}

async fn speak() {
    let hold = vec![say(), greet()];
    let results = join_all(hold).await;
}

async fn say() {
    println!("hello");
}

async fn greet() {
    println!("world");
}

voici la sortie du compilateur

error[E0308]: mismatched types
  --> sync\src\main.rs:14:27
   |
14 |     let hold = vec![say(),greet()];
   |                           ^^^^^^^ expected opaque type, found a different opaque type
...
23 | async fn greet(){
   |                 - the `Output` of this `async fn`'s found opaque type
   |
   = note:     expected type `impl core::future::future::Future` (opaque type at <sync\src\main.rs:19:15>)
           found opaque type `impl core::future::future::Future` (opaque type at <sync\src\main.rs:23:17>)
   = note: distinct uses of `impl Trait` result in different opaque types

Réponses

6 Shepmaster Aug 18 2020 at 20:06

Pour deux futurs, comme vous l'avez fait, utilisezfuture::join

use futures::{executor, future}; // 0.3.5

async fn speak() {
    let (_s, _g) = future::join(say(), greet()).await;
}

Il existe des variantes pour les contrats à terme à trois, quatre et cinq entrées : join3, join4, join5.

Il y a aussi try_join(et try_join3, try_join4, try_join5) pour quand votre futur retourne un Result.

La macro joinest un autre moyen de gérer un nombre statique de futurs à rejoindre.

Si vous devez prendre en charge un nombre dynamique de contrats à terme, vous pouvez utiliser future::join_all(ou try_join_all), mais vous devez disposer d'un vecteur d'un seul type. C'est plus simple via FutureExt::boxed(ou FutureExt::boxed_local):

use futures::{executor, future, FutureExt}; // 0.3.5

async fn speak() {
    let futures = vec![say().boxed(), greet().boxed()];
    let _results = future::join_all(futures).await;
}

Notez que ce code peut exécuter les contrats à terme simultanément mais ne les exécutera pas en parallèle. Pour une exécution parallèle, vous devez introduire un certain type de tâches.

Voir également:

  • Comment puis-je joindre tous les futurs dans un vecteur sans annuler en cas d'échec comme le fait join_all?
  • Rejoindre des contrats à terme avec une simultanéité limitée
  • Comment puis-je effectuer des requêtes HTTP GET asynchrones parallèles avec reqwest ?
  • Comment créer une collection hétérogène d'objets ?
  • Quel est le but de async/wait dans Rust ?
  • Quelle est la différence entre concurrence et parallélisme ?