The code is still running on the UI thread.
It is not running on a background thread.
As such, any lengthy, costly, operation you're doing in that async method will still block the UI for that period of time.
Thread.Sleep
puts the UI thread to sleep.
You need to understand how async
and await
works in this case.
await
here basically says this:
Let's split the method in two here. The first portion is whatever executes up to the point of the await
. The second portion is whatever should execute after the awaitable object has completed.
So, basically, the method executes up until it reaches await Task.Delay(5000);
. Then it puts a "delay of 5 seconds" into play, and says "schedule the rest of the code to execute when that is done". Then it returns so that the UI thread can keep pumping messages.
Once the 5 seconds is up, the UI thread executes the rest of that method.
Basically, this is good if you do asynchronous I/O, but not so good if you do costly operations, like processing large datasets or similar.
So how then can you do that?
You can use Task.Run
.
This will spin up another thread to execute the delegate it is given, and the UI thread is free to do other stuff in the meantime.
Basically you can think of a method using await
as this:
Life of method: <------------------------------------------------------->
Parts: [ start of method ----][awaitable][ rest of method -----]
So the method will execute the first portion, until it reaches await X
, then it will check if X is already done, if it's not done, it will set up some Task
objects in such a way that the awaitable
object gets to run, and once it has completed, the "rest of the method" gets to run.
If X was already done, perhaps it's an asynchronous I/O operation that has already completed, or it completed really fast, then the method will keep executing the rest of the method as though you hadn't written await
there.
But if not, then it returns. This is important, because it lets the UI thread (in this case) get back to pumping messages like mouse clicks and things from the user.
Once the task waiting for that "awaitable object" is told that the awaitable is completed, the "rest of the method" is scheduled, which basically (in this case) puts a message into the message queue asking it to execute the rest of that method.
The more await
statements you have in such a method, the more pieces, basically it will just split the method up into more parts.
You can do all of this with the Task
class that was introduced in an earlier .NET version. The whole purpose of async
/ await
is to make it easier to write code, since wrapping up your code in task objects had the unfortunate effect of turning your code inside out, and making it hard to handle things like exceptions and loops.