I have just tested something that I was sure would fail miserably, but to my surprise, it worked flawlessly, and proves to myself that I am still quite mystified by how async-await
works.
I created a thread, passing an async void
delegate as the thread's body.
Here's an oversimplification of my code:
var thread = new Thread( async () => {
while( true ) {
await SomeLengthyTask();
...
}
});
thread.Start();
thread.Join();
The thing is that as far as I understand, when the execution hits the await
keyword, there is an implicit return from the method, in this case the body of the looping thread, while the rest of the code is wrapped in a callback continuation.
Because of this fact, I was pretty sure that the thread would terminate as soon as the await
yielded execution, but that's not the case!
Does anybody know how this magic is actually implemented? Is the async
functionality stripped down and the async
waits synchronously or is there some black magic being done by the CLR that enables it to resume a thread that has yielded because of an await
?
The thread is indeed terminated very quickly.
But since the Thread
constructor doesn't accept an async
lambda what you got there is an async void
delegate.
The original thread will end and the continuation (the rest after the await
) will be posted to the ThreadPool
and eventually run on another thread.
You can test that by checking the thread id:
var thread = new Thread(async () =>
{
while (true)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await SomeLengthyTask();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
});
thread.Start();
thread.Join();
Console.ReadLine();
Output:
3
5
5
...
5
To make the example simpler let's assume you have this Run
method:
void Run(Action action)
{
action();
}
And you call it with your async
delegate
Run(async () =>
{
while(true)
{
await SomeLengthyTask();
...
}
});
The execution of Run
will complete almost immediately when it reaches the first await
and returns. The rest of the async
delegate will continue on the ThreadPool
with another thread.
Generally, each time you reach an await
in the execution of an async
method the thread is lost and the continuation (the rest after the awaited task completes) will be posted to the ThreadPool (unless if there's a SynchronizationContext present, like in the UI thread). It may be that it execution will be on the same thread (as in my example with 5) but it also may not.
In your case the thread you create explicitly isn't part of the ThreadPool
so it will definitely be terminated and the rest will run on a different thread.
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