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 awaits 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 awaits 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?
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 –
awaitis 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: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:
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.