I'm following the await tutorial on the MSDN, and I'm trying to figure out the difference between using await
as a statement versus using await
as an expression. This whole async-await thing is bending my mind and I can't find any examples for this particular case.
Basically, I wanted to see how to use multiple await
s asynchronously, meaning I don't want to have to wait for the first one to complete before the second one begins. This, to me, defeats the purpose of asynchrony to begin with:
private async void button1_Click(object sender, EventArgs e)
{
// Using await as an expression
string result_a = await WaitAsynchronouslyAsync();
string result_b = await WaitAsynchronouslyAsync();
// This takes six seconds to appear
textBox1.Text = result_a + Environment.NewLine;
textBox1.Text += result_b;
}
public async Task<string> WaitAsynchronouslyAsync()
{
await Task.Delay(3000);
return "Finished";
}
However, with a subtle change it only takes 3 seconds total for the two "Finished"s to appear, which is what I'd want -- the two await
s running truly asynchronously:
private async void button1_Click(object sender, EventArgs e)
{
var a = WaitAsynchronouslyAsync();
var b = WaitAsynchronouslyAsync();
// Using await as a statement
await a;
await b;
// This takes three seconds to appear
textBox1.Text = a.Result + Environment.NewLine;
textBox1.Text += b.Result;
}
My question is, why do these behave differently? What subtle point am I missing here?
Description. The await expression causes async function execution to pause until a promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled promise.
An await is an asynchronous wait. It is not a blocking call and allows the caller of your method to continue. The remainder of the code inside the method after an await will be executed when the Task returned has completed. In the first version of your code, you allow callers to continue.
Answers. Always follow the standard async/await programming pattern from top down. Do not use . Result() as it is only used to invoke an async method from synchronous code.
The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, the await operator returns the result of the operation, if any.
Firstly, you need to distinguish between parallelism and asynchrony. In the first case, it could easily still be worth performing the operations synchronously (and indeed the second operation may depend on the results of the first) in order to free up the UI thread etc.
But as for why they behave differently - await
is only an expression. It's the kind of expression which can appear as a statement, but it will behave the same way, just like calling a method which returns a string, but ignoring the return value. You can see that by changing your first code to:
// Still takes 6 seconds...
var a = WaitAsynchronouslyAsync();
await a;
var b = WaitAsynchronouslyAsync();
await b;
That will still take 6 seconds. The point is that you're only starting the second asynchronous operation after you've waited for the first one to finish. In your second example, both asynchronous operations occur at the same time.
You can still do that and assign the value to a variable, you just need to remember the awaitables:
// This will only take 3 seconds
var a = WaitAsynchronouslyAsync();
var b = WaitAsynchronouslyAsync();
string result_a = await a;
string result_b = await b;
So basically, the difference isn't to do with statement/expression - it's to do with whether the sequence is start/await/start/await or start/start/await/await.
In both situations the await keyword introduces asynchrony. The reason you're seeing the difference is that in case 1 you start both tasks sequentially, where in case 2 you let them run in parallel.
Maybe a step by step explanation of both situations clears things up
string result_a = await WaitAsynchronouslyAsync();
string result_b = await WaitAsynchronouslyAsync();
What happens here is:
In the second case:
var a = WaitAsynchronouslyAsync();
var b = WaitAsynchronouslyAsync();
await a;
await b;
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