I was looking at how to use async await, but I do not quite get it when we have multiple methods invoking each other. Should we always use await or should we only use await when we are actually ready to use the result?
So for example should we do it like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
async Task<string> Func1()
{
return await Func2();
}
async Task<string> Func2()
{
return await tcpClient.ReadStringAsync();
}
Or like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
Task<string> Func1()
{
return Func2();
}
Task<string> Func2()
{
return tcpClient.ReadStringAsync();
}
Per example 1, should we always use await in every method?
Or
Per example 2 should we only use await on the top-most method when we start using the result?
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.
all the two await calls can be started before either one is resolved. The answer is misleading. The jsbin code appears to be executing promises in parallel, but they are not.
Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns.
Use of async and await enables the use of ordinary try / catch blocks around asynchronous code. Note: The await keyword is only valid inside async functions within regular JavaScript code. If you use it outside of an async function's body, you will get a SyntaxError .
Every-time you call await
it creates a lump of code to bundle up variables, captures the synchronization context (if applicable) and create a continuation into an IAsyncStateMachine
.
Essentially, returning a Task
without the async
keyword will give you a small run-time efficiency and save you a bunch of CIL. Do note that the Async feature in .NET also has many optimizations already. Also note (and importantly) that returning a Task
in a using
statement will likely throw an Already Disposed Exception.
You can compare the CIL and plumbing differences here
So if your method is just forwarding a Task
and not wanting anything from it, you could easily just drop the async
keyword and return the Task
directly.
More-so, there are times when we do more than just forwarding and there is branching involved. This is where, Task.FromResult
and Task.CompletedTask
come into play to help deal with the logic of what may arise in a method. I.e If you want to give a result (there and then), or return a Task
that is completed (respectively).
Lastly, the Async and Await Pattern has subtle differences when dealing with Exceptions. If you are returning a Task
, you can use Task.FromException<T>
to pop any exception on the the returned Task
like an async
method would normally do.
Nonsensical example
public Task<int> DoSomethingAsync(int someValue)
{
try
{
if (someValue == 1)
return Task.FromResult(3); // Return a completed task
return MyAsyncMethod(); // Return a task
}
catch (Exception e)
{
return Task.FromException<int>(e); // Place exception on the task
}
}
In short, if you don't quite understand what is going on, just await
it; the overhead will be minimal. However, if you understand the subtitles of how to return a task result, a completed task, placing an exception on a task, or just forwarding. You can save your self some CIL and give your code a small performance gain by dropping the async
keyword returning a task directly and bypassing the IAsyncStateMachine
.
At about this time, I would look up the Stack Overflow user and author Stephen Cleary, and Mr. Parallel Stephen Toub. They have a plethora of blogs and books dedicated solely to the Async and Await Pattern, all the pitfalls, coding etiquette and lots more information you will surely find interesting.
Both options are legit and each option has own scenarios where it is more effective then another.
Of course always use await when you want to handle result of the asynchronous method or handle possible exception in current method
public async Task Execute()
{
try
{
await RunAsync();
}
catch (Exception ex)
{
// Handle thrown exception
}
}
If you don't use result of asynchronous method in current method - return the Task. This approach will delay state machine creation to the caller or where ever final task will be awaited. As pointed in the comments can make execution little bit more effective.
But there are scenarios where you must await for the task, even you do nothing with result and don't want handle possible exceptions
public Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return context.Entities.FindAsync(id);
}
}
In the scenario above, FindAsync
can return not completed task and this task will be returned straight away to the caller and dispose context
object created within using
statement.
Later when caller will "await" for the task exception will be thrown because it will try to use already disposed object(context
).
public async Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return await context.Entities.FindAsync(id);
}
}
And traditionally answers about Async Await must include link to Stephen Cleary's blog
Eliding Async and Await
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With