Using await
does not wait, that is the whole point. If you want to wait, you use Task.Wait
.
However, the execution of the async
method will only resume after the awaited task is completed (it is a continuation). Let us see your async
method:
private static async Task Run(Action action)
{
await Task.Run(action);
// There is nothing here
}
There is no code to execute after the task is done... Alright, the async
method returns a task that completes when it is done. Let us see if you await
that...
Run(() => LongProcess()).ContinueWith( t => Run(() => LongerProcess()));
You don't. You fire that task and forget about it.
I think this is what you want:
static async void Main(string[] args)
{
await Run(() => LongProcess());
await Run(() => LongerProcess());
int count = 5;
do
{
Console.WriteLine(count.ToString());
Thread.Sleep(100);
count++;
} while (count < 20);
Console.ReadKey();
}
Note: Async Main is a C# 7.1 feature.
This code will run the task that invokes LongProcess
, and then as a continuation the task that runs LongerProcess
, and then as a continuation the rest of the code.
Why would you want that instead of just calling these methods synchronously is beyond me.
By the way, in an async
method you can use await Task.Delay(milliseconds)
instead of Thread.Sleep(milliseconds)
. The advantage is that the thread is not waiting. It like making a continuation on a single execution timer.
If async/await
is just continuations, you might be wondering why would people want to use them instead of ContinueWith
.
Let me give you a few reasons:
- Code with
async/await
is easier to read. Less nested stuff clouding the code. You can understand what the code does independently of understanding threading.
- Code with
async/await
is easier to write. You just write it as if it were all synchronous, with some async
and await
sparkled in there. You can write synchronous code and then worry how to make it concurrent. You also end up writing less, which means you are more productive.
- Code with
async/await
is smarter™. The compiler rewrites your code as a continuation state machine, allowing you to put await
inside statements without any code gymnastics™. And this extends to exception handling. You see, in your fire and forget task continuation, you are not handling exceptions. What if LongerProcess
throws? Well, with async/await
you can just put the await
inside of a try ... catch
and it does the right thing™.
That is all good separation of concerns.
You may also wonder in what situation it is a good idea to use async/await
instead of synchronous code. And the answer is that it shines when dealing with I/O operations. When interacting with an external system it is common to not have a response right away. For example, if you want to read from disk or download from the network.
In fact, if you consider manipulating a form and handling its event to be I/O bound operations (because, they are). You will see that they are a good place to use async/await
. In particular given that the synchronization context for UI threads will keep continuations on the same thread by default. You can, of course, use async/await
with CPU bound operations by using Task.Run
. When is that a good idea? Ah, yes, when you want to keep the UI responsive.