5

我正在关注 MSDN 上的await教程,并试图找出 using awaitas a statement与 using awaitas an expression之间的区别。这整个 async-await 事情让我心烦意乱,我找不到这个特殊情况的任何例子。

基本上,我想看看如何await异步使用多个 s,这意味着我不想在第二个开始之前等待第一个完成。对我来说,这违背了异步的目的:

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";
}

然而,通过一个细微的改变,两个“Finished”的出现总共只需要 3 秒,这就是我想要的——这两个awaits 真正异步运行:

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;
}

我的问题是,为什么这些行为不同?我在这里错过了什么微妙的点?

4

2 回答 2

11

首先,你需要区分并行异步。在第一种情况下,很容易仍然值得同步执行操作(实际上第二个操作可能取决于第一个操作的结果)以释放 UI 线程等。

但至于为什么他们的行为不同 -只是await一种表达。这是一种可以作为语句出现的表达式,但它的行为方式相同,就像调用返回字符串但忽略返回值的方法一样。您可以通过将第一个代码更改为:

// Still takes 6 seconds...
var a = WaitAsynchronouslyAsync();
await a;

var b = WaitAsynchronouslyAsync();
await b;

这仍然需要 6 秒。关键是您在等待第一个异步操作完成后才开始第二个异步操作。在您的第二个示例中,两个异步操作同时发生。

您仍然可以这样做并将值分配给变量,您只需要记住等待对象:

// This will only take 3 seconds
var a = WaitAsynchronouslyAsync();
var b = WaitAsynchronouslyAsync();
string result_a = await a;
string result_b = await b;

所以基本上,区别与语句/表达式无关 - 它与序列是开始/等待/开始/等待还是开始/开始/等待/等待有关。

于 2012-09-19T21:12:23.740 回答
4

在这两种情况下,await 关键字都会引入异步。您看到差异的原因是,在案例 1 中,您按顺序启动两个任务,而在案例 2 中,您让它们并行运行。

也许对这两种情况的逐步解释可以解决问题

string result_a = await WaitAsynchronouslyAsync(); 
string result_b = await WaitAsynchronouslyAsync(); 

这里发生的是:

  • 任务 (a) 开始
  • 等待任务 a(控制权返回给调用者)
  • 当任务a在3秒后完成时,方法继续;任务 (b) 开始
  • 等待任务 b(控制权返回给调用者)
  • 当任务 b 再过 3 秒后完成时,会出现文本

在第二种情况下:

var a = WaitAsynchronouslyAsync();     
var b = WaitAsynchronouslyAsync();     
await a;     
await b;     
  • 任务 (a) 开始
  • 任务 (b) 开始
  • 任务 (a) 被“等待”(即,控制权返回给调用者)
  • 当任务(a)在 3 秒后完成时,等待任务(b)
  • 由于任务 b 大约在 3 秒前开始,它或多或少与(a)同时完成
  • 文字出现
于 2012-09-19T21:20:26.317 回答