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

时间:2017-06-23 09:44:30

标签: c# .net async-await

我们说我有两个异步方法

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秒
谁能解释为什么?方法几乎相同。有什么不同?

4 个答案:

答案 0 :(得分: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

第二种方法:

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

答案 1 :(得分: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
}

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

虽然是第二种方法,

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相同的结果。

答案 2 :(得分:6)

在第一种情况下,你说

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返回;
  6. 第二种情况是

    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. 创建回调
    3. 0:00在2秒0:00
    4. 创建回调
    5. 0:00等待第一次回调0:02
    6. 0:02等待第二次回调0:02
    7. 0:02返回
    8. 换句话说,第一个是顺序异步编程,第二个是并行异步编程。

答案 3 :(得分:5)

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

时启动

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