I was reading about async/await
keywords and I've read that:
When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
Well, I've created a simple windows forms application
, placed two labels, a button and a textbox and I wrote the code:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = Thread.CurrentThread.ThreadState.ToString();
button1.Text = await DoWork();
label2.Text = Thread.CurrentThread.ThreadState.ToString();
}
private Task<string> DoWork()
{
return Task.Run(() => {
Thread.Sleep(10000);
return "done with work";
});
}
What I don't understand is that when I click the button, the label1 will have the text Running
and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
So, how does the async/await works?
here is a "screenshot" from the book:
Regards
The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.
You create your new async Task from your UI code on the main thread — and now this happens! Remember, you learned that every use of await is a suspension point, and your code might resume on a different thread. The first piece of your code runs on the main thread because the task initially runs on the main actor.
A good way to think about this is to imagine that asynchronous methods have “pause” and “play” buttons. When the executing thread reaches an await expression, it hits the “pause” button and the method execution is suspended.
An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method. The async and await keywords don't cause additional threads to be created.
It has its own scheduling context, which schedules new work by sending it through the message queue back on the UI thread. This means that if you’re running on the UI thread and await a task, when the result of the task is ready, the rest of the asynchronous method will run back on the UI thread.
Async methods behave logically similar to non- async methods, at least until the first await, and therefore the first context switch occurs. Up until this point, everything will execute synchronously. So in our case: The first call to DoStuff () starts, and sleeps for 500ms.
So this is what an asynchronous method should do when it awaits a task: On suspension: Ask the thread it’s running on for its scheduling context. On resumption: Schedule the resumption delegate back on that scheduling context. Why is this important? Consider the UI thread.
Even with the async-await pattern! That is normal, the program does not create a Task on a separate thread and therefore all the code is still executed on the UI thread. Only using the async/await keywords is not enough to make the code asynchronous.
I've read that: When the flow of logic reaches the await token, the calling thread is suspended until the call completes.
Where did you read that nonsense? Either there is some context there that you're not quoting, or you should stop reading whatever text it is that contained this. The point of await is to do the opposite of that. The point of await is to keep the current thread doing useful work while the asynchronous task is in flight.
UPDATE: I downloaded the book you referenced. Absolutely everything in that section is wrong. Throw this book away and buy a better book.
What I don't understand is that when I click the button, the label1 will have the text Running and the label will have the same text only after 10 seconds, but in these 10 seconds I was able to enter the text in my textbox, so it seems that the main thread is running...
That's correct. Here's what happens:
label1.Text = Thread.CurrentThread.ThreadState.ToString();
The text is set.
button1.Text = await DoWork();
A bunch of stuff happens here. What happens first? DoWork
is called. What does it do?
return Task.Run(() => { Thread.Sleep(10000);
It grabs a thread out of the thread pool, puts that thread to sleep for ten seconds, and returns a task representing the "work" being done by that thread.
Now we are back here:
button1.Text = await DoWork();
We have a task in hand. Await first checks the task to see if it is already complete. It is not. Next it signs up the remainder of this method as the continuation of the task. Then it returns to its caller.
Hey, what is its caller? How did we get here anyways?
Some code called this event handler; it was the event loop that is processing Windows messages. It saw a button was clicked and dispatched to the click handler, which has just returned.
Now what happens? The event loop keeps running. Your UI keeps on running nicely, as you noticed. Eventually that thread ticks off ten seconds and the task's continuation is activated. What does that do?
That posts a message into the Windows queue saying "you need to run the rest of that event handler now; I have the result you were looking for."
The main thread event loop eventually gets to that message. So the event handler picks up where it left off:
button1.Text = await DoWork();
The await now extracts the result from the task, stores it in the button text, and returns back to the event loop.
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