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

Rom*_*syk 24 .net c# async-await

假设我有两种异步方法

public async static Task RunAsync1()
{
    await Task.Delay(2000);
    await Task.Delay(2000);
}
Run Code Online (Sandbox Code Playgroud)

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

    await t1;
    await t2;
}
Run Code Online (Sandbox Code Playgroud)

然后我就像使用它一样

public static void M()
{
    RunAsync1().GetAwaiter().GetResult();
    RunAsync2().GetAwaiter().GetResult();
}
Run Code Online (Sandbox Code Playgroud)

结果RunAsync1将运行4 RunAsync2只有2秒
可以解释为什么?方法几乎相同.有什么不同?

Evk*_*Evk 57

在第二种方法中,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
Run Code Online (Sandbox Code Playgroud)

第二种方法:

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
Run Code Online (Sandbox Code Playgroud)

  • 这不是变量的问题,而是你何时何地使用`await`.如果你做`var t1 = Task.Delay(2000);`然后`等待t1;`,你会得到相同的结果. (10认同)

Pab*_*sso 14

检查你的代码:

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
}
Run Code Online (Sandbox Code Playgroud)

所以第二个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
}
Run Code Online (Sandbox Code Playgroud)

因此任务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
}
Run Code Online (Sandbox Code Playgroud)

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


Aro*_*ron 6

在第一种情况下,你说

public async static Task RunAsync1()
{
    var t1 = Task.Delay(2000);
    await t1;
    var t2 = await Task.Delay(2000);
    await t2;
}
Run Code Online (Sandbox Code Playgroud)

这相当于

  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;
}
Run Code Online (Sandbox Code Playgroud)
  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回来

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


Tha*_*ina 5

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

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