9

I have tried Tokio tasks, but there are no working examples to execute multiple tasks at once. What is wrong with this 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");
}

here is the compiler output

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
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Alexei Kitaev
  • 159
  • 1
  • 4
  • 1
    Why not use the [`join!`](https://docs.rs/futures-util/0.3.5/futures_util/macro.join.html) macro? – rodrigo Aug 18 '20 at 08:34
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Aug 18 '20 at 12:50

1 Answers1

12

For two futures, like you have, use future::join

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

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

There are variants for three, four, and five input futures: join3, join4, join5.

There is also try_join (and try_join3, try_join4, try_join5) for when your future returns a Result.

The macro join is another way to handle a static number of futures to join.

If you need to support a dynamic number of futures, you can use future::join_all (or try_join_all), but you have to have a vector of all one kind. This is easiest via FutureExt::boxed (or 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;
}

Note that this code can run the futures concurrently but will not run them in parallel. For parallel execution, you need to introduce some kind of tasks.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Please mark the accepted answer to this question. This answer helped me when I had the same question. – spdrman Oct 03 '22 at 19:23