Как выполнить сразу несколько асинхронных функций и получить результат?

Aug 18 2020

Я пробовал задачи Tokio, но нет рабочих примеров для одновременного выполнения нескольких задач. Что не так с этим кодом?

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

вот вывод компилятора

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

Ответы

6 Shepmaster Aug 18 2020 at 20:06

Для двух фьючерсов, как и у вас, используйте future::join

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

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

Есть варианты три, четыре, и пять входных фьючерсов: join3, join4, join5.

Существует также try_join(и try_join3, try_join4, try_join5), когда ваше будущее возвращает Result.

Макрос join- это еще один способ обработки статического количества фьючерсов, к которым нужно присоединиться.

Если вам нужно поддерживать динамическое количество фьючерсов, вы можете использовать future::join_all(или try_join_all), но у вас должен быть вектор всего одного вида. Проще всего это сделать с помощью FutureExt::boxed(или 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;
}

Обратите внимание, что этот код может запускать фьючерсы одновременно, но не будет запускать их параллельно. Для параллельного выполнения нужно ввести какие-то задачи.

Смотрите также:

  • Как я могу присоединиться ко всем фьючерсам в векторе без отмены в случае неудачи, как это делает join_all?
  • Присоединяйтесь к фьючерсам с ограниченным параллелизмом
  • Как я могу выполнять параллельные асинхронные HTTP-запросы GET с помощью reqwest?
  • Как мне создать разнородную коллекцию объектов?
  • Какова цель async / await в Rust?
  • В чем разница между параллелизмом и параллелизмом?