在几乎相同的方法中异步/等待的行为不同

假设我有两种异步方法

public async static Task RunAsync1() { await Task.Delay(2000); await Task.Delay(2000); } 

 public async static Task RunAsync2() { var t1 = Task.Delay(2000); var t2 = Task.Delay(2000); await t1; await t2; } 

然后我就像使用它一样

 public static void M() { RunAsync1().GetAwaiter().GetResult(); RunAsync2().GetAwaiter().GetResult(); } 

结果, RunAsync1将运行4 秒,RunAsync2仅运行2秒
任何人都可以解释原因吗? 方法几乎相同。 有什么不同?

在第二种方法中,2个任务同时开始。 它们都将在2秒内完成(因为它们并行运行)。 在第一种方法中,首先运行一种方法(2秒),等待它完成,然后再启动第二种方法(2秒钟)。 这里的关键点是Task.Delay(..)在你调用它时启动,而不是等待它。

为了澄清更多,第一种方法:

 var t1 = Task.Delay(2000); // this task is running now await t1; // returns 2 seconds later var t2 = Task.Delay(2000); // this task is running now await t2; // returns 2 more seconds later 

第二种方法:

 var t1 = Task.Delay(2000); var t2 = Task.Delay(2000); // both are running now await t1; // returns in about 2 seconds await t2; // returns almost immediately, because t2 is already running for 2 seconds 

只需检查您的代码:

 public async static Task RunAsync1() { await Task.Delay(2000); // Start a delay task, and WAIT for it to finish await Task.Delay(2000); // Start a delay task, and WAIT for it to finish } 

所以第二个await Task.Delay(2000); 在第一次通话结束后(2秒后)调用。

而第二种方法,

 public async static Task RunAsync2() { var t1 = Task.Delay(2000); // Start a task var t2 = Task.Delay(2000); // Start a task await t1; // Wait for task to finish await t2; // Wait for task to finish } 

因此任务t1和t2同时运行。

如果你改成它

 public async static Task RunAsync3() { var t1 = Task.Delay(2000); // Start a task await t1; // Wait for task to finish var t2 = Task.Delay(2000); // Start a task await t2; // Wait for task to finish } 

你会得到与RunAsync1相同的结果。

在第一种情况下,你说

 public async static Task RunAsync1() { var t1 = Task.Delay(2000); await t1; var t2 = await Task.Delay(2000); await t2; } 

这相当于

  1. 0:00在2秒0:00内创建一个回调
  2. 0:00等待回调0:02返回
  3. 0:02在2秒内创建一个回调0:02
  4. 0:02等待回调0:04返回
  5. 0:04返回;

第二种情况是

 public async static Task RunAsync2() { var t1 = Task.Delay(2000); var t2 = Task.Delay(2000); await t1; await t2; } 
  1. 0:00在2秒0:00创建回调
  2. 0:00在2秒0:00创建回调
  3. 0:00等待第一次回调0:02
  4. 0:02等待第二回调0:02
  5. 0:02回归

换句话说,在第一个中,您正在进行顺序异步编程,第二个是并行异步编程。

每当你开始一个任务。 它已经在您创建它时启动,而不是在您调用await

如果您创建一个任务并将其放在一个变量中,那么当您等待它时它可能已经完成。 这就是你的第二个案件。 await确保它必须在继续之前完成。