Come eseguire più funzioni asincrone contemporaneamente e ottenere i risultati?

Aug 18 2020

Ho provato le attività Tokio, ma non ci sono esempi funzionanti per eseguire più attività contemporaneamente. Cosa c'è di sbagliato in questo codice?

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");
}

ecco l'output del compilatore

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

Risposte

6 Shepmaster Aug 18 2020 at 20:06

Per due futuri, come te, usafuture::join

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

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

Ci sono varianti per tre, quattro e cinque input futures: join3, join4, join5.

C'è anche try_join(e try_join3, try_join4, try_join5) per quando il tuo futuro restituisce un Result.

La macro joinè un altro modo per gestire un numero statico di future a cui aderire.

Se hai bisogno di supportare un numero dinamico di futures, puoi usare future::join_all(o try_join_all), ma devi avere un vettore di un solo tipo. Questo è più semplice tramite FutureExt::boxed(o 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;
}

Si noti che questo codice può eseguire i future contemporaneamente ma non li eseguirà in parallelo. Per l'esecuzione parallela, è necessario introdurre alcuni tipi di attività.

Guarda anche:

  • Come posso unire tutti i futures in un vettore senza annullare in caso di errore come fa join_all?
  • Unisciti ai futures con concorrenza limitata
  • Come posso eseguire richieste GET HTTP asincrone parallele con reqwest?
  • Come faccio a creare una collezione eterogenea di oggetti?
  • Qual è lo scopo di async/await in Rust?
  • Qual è la differenza tra concorrenza e parallelismo?