¿Cómo ejecutar múltiples funciones asíncronas a la vez y obtener los resultados?

Aug 18 2020

He probado las tareas de Tokio, pero no hay ejemplos de trabajo para ejecutar varias tareas a la vez. ¿Qué está mal con este código?

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

aquí está la salida del compilador

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

Respuestas

6 Shepmaster Aug 18 2020 at 20:06

Para dos futuros, como el tuyo, usafuture::join

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

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

Existen variantes para futuros de tres, cuatro y cinco entradas: join3, join4, join5.

También hay try_join(y try_join3, try_join4, try_join5) para cuando tu futuro devuelva un Result.

La macro joines otra forma de manejar un número estático de futuros para unirse.

Si necesita admitir un número dinámico de futuros, puede usar future::join_all(o try_join_all), pero debe tener un vector de un solo tipo. Esto es más fácil a través FutureExt::boxedde (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;
}

Tenga en cuenta que este código puede ejecutar los futuros al mismo tiempo, pero no los ejecutará en paralelo. Para la ejecución en paralelo, debe introducir algún tipo de tareas.

Ver también:

  • ¿Cómo puedo unir todos los futuros en un vector sin cancelar en caso de falla como lo hace join_all?
  • Únase a futuros con concurrencia limitada
  • ¿Cómo puedo realizar solicitudes GET HTTP asincrónicas paralelas con reqwest?
  • ¿Cómo creo una colección heterogénea de objetos?
  • ¿Cuál es el propósito de async/await en Rust?
  • ¿Cuál es la diferencia entre concurrencia y paralelismo?