Como executar várias funções assíncronas ao mesmo tempo e obter os resultados?

Aug 18 2020

Eu tentei as tarefas do Tokio, mas não há exemplos de trabalho para executar várias tarefas ao mesmo tempo. O que está errado neste 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");
}

aqui está a saída do 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

Respostas

6 Shepmaster Aug 18 2020 at 20:06

Para dois futuros, como você, usefuture::join

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

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

Existem variantes para três, quatro e cinco futuros de entrada: join3, join4, join5.

Há também try_join(e try_join3, try_join4, try_join5) para quando seu futuro retornar um Result.

A macro joiné outra maneira de lidar com um número estático de futuros para ingressar.

Se você precisar oferecer suporte a um número dinâmico de futuros, poderá usar future::join_all(ou try_join_all), mas precisará ter um vetor de um único tipo. Isso é mais fácil 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;
}

Observe que esse código pode executar os futuros simultaneamente, mas não os executará em paralelo. Para execução paralela, você precisa introduzir algum tipo de tarefa.

Veja também:

  • Como posso juntar todos os futuros em um vetor sem cancelar em caso de falha como join_all faz?
  • Junte-se a futuros com simultaneidade limitada
  • Como posso executar solicitações GET HTTP assíncronas paralelas com reqwest?
  • Como faço para criar uma coleção heterogênea de objetos?
  • Qual é o propósito de async/await no Rust?
  • Qual é a diferença entre concorrência e paralelismo?