Reputation: 5704
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);
}
Upvotes: 3
Views: 762
Reputation: 24535
What's the difference between awaiting
async Task
function and callingawait
inside avoid
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", i.e.; 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
Upvotes: 3
Reputation:
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
Upvotes: 4
Reputation: 192
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);
Upvotes: -1