Search code examples
rustrust-tokio

tokio::join and different results


First I wrote the first implementation, then tried to simplify it to the second one, but surprisingly the second one is almost 3x slower. Why?

First implementation (faster):

let data: Vec<Arc<Data>> = vec![d1,d2,d3];

let mut handles = Vec::new();
for d in &data {
   let d = d.clone();
   handles.push(tokio::spawn(async move {
     d.update().await;
   }));
}

for handle in handles {
   let _ = tokio::join!(handle);
}

Second implementation (slower):

let data: Vec<Arc<Data>> = vec![d1,d2,d3];

for d in &data {
   let d = d.clone();
   let _ = tokio::join!(tokio::spawn(async move {
     d.update().await;
   }));
}

Solution

  • In the first example you spawn all your tasks onto the executor, allowing them to run in parallel, and then you join all of them in sequence. In the second example you spawn each task onto the executor in sequence, but you wait for that task to finish before spawning the next one, meaning you get zero parallelism, and thus no speedup. Again, the important observation to make is that in the first example all of your tasks are making progress in the background even though you're waiting for them to finish one by one. Also something like join_all would probably be more appropriate for waiting on the tasks in the first example.