0

Cannot seem to get the futures:join macro to execute in parallel using tokio::main.

Cargo.toml

[dependencies]
futures = "0.3"
tokio = { version = "1", features = ["full"] }

main.rs

use futures::join;
use std::time::{Duration, Instant};
use std::thread;

async fn do_io() { thread::sleep(Duration::from_millis(250)); }

async fn fetch() -> ((), ()) {
    join!(do_io(), do_io())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let s = Instant::now();
    fetch().await;
    let d = s.elapsed();
    println!("{:?}", d);
    Ok(())
}

Expected Output

~250ms

Actual Output

~500ms

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
webish
  • 701
  • 2
  • 9
  • 17
  • 3
    `std::thread::sleep` will sleep synchronously, blocking the executor thread. You want to use [`tokio::time::sleep`](https://docs.rs/tokio/1.2.0/tokio/time/fn.sleep.html) instead. – apilat Feb 08 '21 at 17:15
  • @apilat, so `futures::join` joins the futures onto the same thread and `thread::sleep` is a blocking call per future rather than async io... _nice_ – webish Feb 08 '21 at 17:47
  • @webish kinda? `futures::join` will basically pack the futures together but all of that will be passed as a single unit to the executor, and since your futures don't yield while sleeping (as they're a thread-level sleep) the executor will run the join() future, which will run the first do_io, which will suspend the executor itself for 250ms, then repeat for the second do_io. Tokio actually defaults to a multithreaded runtime, but that works at the [*task*](https://docs.rs/tokio/1.2.0/tokio/fn.spawn.html) granularity. And here you only have the `main` task. – Masklinn Feb 09 '21 at 11:32

0 Answers0