Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the additional outer async block

In a lot of SO questions and also in a lot of external, reputable resources, such as the tokio tutorial I've seen people use an additional async block such as:

tokio::spawn(async move {
    process(socket).await;
});

instead of doing just

tokio::spawn(process(socket));

Both resolve to some Future and spawn() expects

pub fn spawn<T>(future: T) ....
where T: Future + ....

so I cannot understand the need for the additional async {} block.

Is it really necessary ? And is there any difference besides being a "visual marking" that this is an async code?

like image 928
Svetlin Zarev Avatar asked Aug 16 '21 17:08

Svetlin Zarev


People also ask

What is the purpose of async function?

Note: The purpose of async / await is to simplify the syntax necessary to consume promise-based APIs. The behavior of async / await is similar to combining generators and promises. Async functions always return a promise.

What is the purpose of async await keywords?

An async keyword is a method that performs asynchronous tasks such as fetching data from a database, reading a file, etc, they can be marked as “async”. Whereas await keyword making “await” to a statement means suspending the execution of the async method it is residing in until the asynchronous task completes.

What is the benefit of async?

Benefits of Asynchronous ProgrammingImprove your application's performance and responsiveness, especially if you have long-running operations that don't require blocking the execution. In this case, you can do other things while you wait for the long-running Task to finish.

What is the role of the async method in C#?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.


1 Answers

These are slightly different, depending on the implementation of process.

If process is defined like this:

fn process(socket: Socket) -> impl Future {
    // non-async stuff
    println!("non-async stuff");

    // async stuff
    async {
        println!("async stuff");
    }
}

Then invoking it with tokio::spawn(process(socket)); will execute the first line immediately and only the remaining sub-task, which prints "async stuff", will be scheduled.

If it defined like this:

async fn process(socket: Socket) {
    // non-async stuff
    println!("non-async stuff");

    // async stuff
    async {
        println!("async stuff");
    }.await;
}

Then tokio::spawn(process(socket)); will initally do nothing and will print both "non-async stuff" and "async stuff" when the scheduled task is executed.

Wrapping the call in a extra async block will make the two versions behave the same way. Whether or not this is the reason for the extra async block or if it is "needed" in the examples that you've seen is a question for the authors of those examples.

like image 155
Peter Hall Avatar answered Oct 17 '22 16:10

Peter Hall