What is the difference between tokio::spawn(my_future).await and just my_future.await?

Viewed 6015

Given an async function and it's corresponding future, lets say:

async fn foo() -> Result<i32, &'static str> {
    // ...
}

let my_future = foo();

what is the difference between awaiting it using just .await other than using tokio::spawn().await?

// like this...
let result1 = my_future.await;

// ... and like this
let result2 = tokio::spawn(my_future).await;
1 Answers

One typically doesn't await a spawned task (or at least not right away). It's more common to simply write:

tokio::spawn(my_future);

Leave out the .await and the task will run in the background while the current task continues. Immediately calling .await blocks the current task. spawn(task).await is effectively no different than task.await. It's akin to creating a thread and immediately joining it, which is equally pointless.

Spawned tasks don't need to be awaited the way bare futures do. Awaiting them is optional. When might one want to await one, then? If you want to block the current task until the spawned task finishes.

let task = tokio::spawn(my_future);

// Do something else.
do_other_work();

// Now wait for the task to complete, if it hasn't already.
task.await;

Or if you need the result, but need to do work in between starting the task and collecting the result.

let task = tokio::spawn(my_future);

// Do something else.
do_other_work();

// Get the result.
let result = task.await;
Related