简体   繁体   中英

What's the difference between awaiting async Task function and calling await inside a void function?

To understand the question please take a look on the await calls and the definition of the function InitSyncContext() of the following example.

Based on that i would like to know how the program will behave on each scenario because i don't fully understand what´s the difference between calling await InitSyncContext(store) and having a await call inside without returning a Task .

For reference i did a research before and i found a similar example here however i think it's different in my case.

*The following code is a simplified example from a real world code just for demonstration purposes.

void Main()
{
    Initializer();
}

private async void Initializer()
{
    var store = InitLocalStore();
    await InitSyncContext(store); // <-- Here, await call
    InitFileSync(store);
}

// Here returns Task (without having a return inside. No compile errors)
private async Task InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}

//------------- Second Method -------------

void Main()
{
    Initializer();
}

private void Initializer()
{
    var store = InitLocalStore();
    InitSyncContext(store); // <-- Here without await call
    InitFileSync(store);
}

// Here is void but with a async call inside
private async void InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}

What's the difference between awaiting async Task function and calling await inside a void function?

This is perhaps a very big question is best served by reading the fine article Async/Await - Best Practices in Asynchronous Programming by Mr Stephen Cleary.

Some summary points:

Avoid async void - Prefer async Task methods over async void methods

在此输入图像描述

See also

What's the difference between awaiting async Task function and calling await inside a void function?

The whole world! Everything...and then some. Let's take a step back and start with some of the basics.

You should go "async all the way", ie; if you're returning an awaitable ( Task or Task<T> ) these should correctly use the async and await keywords.

There are several things that need to be clarified here. You should not have async void methods, instead you should have async Task - the exception being event handlers (where the delegates are predefined as non-task returning) and the like. Let's examine and pick apart method one (I'm going to ignore the Main entry points):

One

private async void Initializer()
{
    var store = InitLocalStore();
    await InitSyncContext(store); // <-- Here, await call
    ...
}

// Here returns Task (without having a return inside. No compile errors)
private async Task InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}

You have an Initializer method that is immediately a code smell as it is async void . This should be async Task and it should have the "Async" suffix. Additionally, you have an InitSyncContext that takes on a store variable and invokes some client initialization work. The code smell here is that you are using async and await . This is not need on simple (single task) workloads like this. Instead you should simply use the return keyword. Example at the very bottom. Let's look at method two:

Two

private void Initializer()
{
    var store = InitLocalStore();
    InitSyncContext(store); // <-- Here without await call
    ...
}

// Here is void but with a async call inside
private async void InitSyncContext(MobileServiceSQLiteStore store)
{
    await Client.SyncContext.InitializeAsync(store);
}

Things have officially gone from bad to worse! With the misconceptions of the asynchronous nomenclatures, we have assumed that since one method appeared to work "ok" without taking into account the best practices that another method could follow suit. You made the InitSyncContext method async void . The reason methods should not be async void is that they are fire-and-forget. The internal async state machine doesn't have a Task to latch onto and therefore the state is lost. When you remove the caller's await you are saying start this asynchronous operation but you do not care about it's results.

Here is the correct way to implement the desired functionality:

Correct

private async Task InitializerAsync()
{
    var store = InitLocalStore();
    await InitSyncContextAsync(store);
    ...
}

// Simply return the task that represents the async operation and let the caller await it
private Task InitSyncContextAsync(MobileServiceSQLiteStore store)
{
    return Client.SyncContext.InitializeAsync(store);
}

A note about the Main method from your snippets, if this is part of a console application - the top-level entry point into your async stack would invoke either .Result or .Wait() .

Further reading

In first example compiler generate something like this:

TheadPool.RunTask(()=>InitSyncContext(store)).ContinueWith(()=>InitFileSync(store))

At second — nothing interesting. Because nobody wait the end of the task. All calls will be in main thread exept await Client.SyncContext.InitializeAsync(store);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM