65.9K
CodeProject 正在变化。 阅读更多。
Home

等待一个方法与等待一个任务

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.58/5 (10投票s)

2018年7月20日

CPOL

3分钟阅读

viewsIcon

11948

等待方法与等待任务

大多数开发者只是等待方法,而不是等待awaiter返回的Task。awaiter是由被等待的方法返回的东西。

在这篇文章中,我们将研究当我们在方法中多次等待时,等待方法而不是等待任务会发生什么。

用例

在调用代码中有两个可等待的方法,它们可以单独处理。这意味着当第一个await正在发生时,可以发生第二个可等待的调用。

所有的awaiter和awaitable有点令人困惑。如果你不理解这句话,请再读一遍。

开始编码

为了本文的目的,我将在一个控制台应用程序中测试这一点。这是我们的AwaitTest类。

public class AwaitTest  
{  
    public async Task DoSomeThingAsync()  
    {  
        var time = Stopwatch.StartNew();  
  
        //a database call which takes 5 seconds to run  
        await Task.Delay(5000);  
        await PerformCalculationsAsync();  
  
        Console.WriteLine("time taken : " + time.Elapsed);  
    }  

    private async Task<int> PerformCalculationsAsync()  
    {  
        await Task.Delay(2000); //This can be some operation which takes 2 sec.  
        return 30;  
    }  
}

所以,我们的DoSomethingAsync()有两个awaitable。一个需要5秒执行,另一个需要2秒执行。现在,我们将在应用程序的Main方法中调用它,看看它是如何进行的。

以下是如何在应用程序的Main方法中调用我们的async方法。

public class Program  
{  
    static void Main(string[] args)  
    {  
        AwaitTest at = new AwaitTest();  
        at.DoSomeThingAsync().GetAwaiter().GetResult();  
    }  
  
}

DoSomeThingAsync()方法中使用上面的代码,你能猜出操作的计时吗?

那么,DoSomeThingAsync()完成操作所需的时间是

Time taken : 00:00:07.0079634

那么,当我们等待方法时发生了什么?

它本质上就是这样,但我们需要理解它是如何工作的。因此,当一个方法被等待时,它会等待该方法完成其操作。

我们在DoSomeThingAsync()方法中的第一个awaiter

await Task.Delay(5000);

上面的行只是等待5秒钟完成其操作。完成操作后,将执行下一个awaiter。

await PerformCalculations();

上面的行需要2秒才能完成其操作。所以这次操作的总时间是07.0079634。

我建议你自己尝试一下,只需在DoSomeThingAsync()方法中放置一个调试器,然后观察它在做什么。

现在使用上面的方法,它看起来就像同步操作一样,因为一次只执行一件事。因此,我们没有获得async-await的好处。

好的,什么会更好?

与其直接等待方法,不如等待Task而不是方法。

我将修改DoSomeThingAsync()方法,以便我们等待Task

public async Task DoSomeThingAsync()  
{  
    var time = Stopwatch.StartNew();  
  
    //a database call which takes 5 seconds to run  
    //await Task.Delay(5000);  
    //await PerformCalculationsAsync();  
  
    Task t1 = Task.Delay(5000);  
    Task t2 = PerformCalculationsAsync();  
  
    await t1;  
    await t2;  
  
    Console.WriteLine("time taken : " + time.Elapsed);  
}

现在,猜猜时间。这是输出

time taken : 00:00:05.0080029

现在改变计时的是什么?

让我们看看代码中发生了什么。

  1. Task t1 = Task.Delay(5000);
  2. Task t2 = PerformCalculationsAsync();

调试时,上面两行会立即返回(但这并不意味着这两个操作没有完成)。相反,t1t2将返回它们自己的Task

  1. await t1;
  2. await t2;

当执行第一个await t1;时,它返回一个Task,然后第二个await t2;将开始执行。因此,在第一个任务完成时,第二个任务将会完成,因为第二个任务需要2秒,而第一个任务需要5秒才能完成。

因此,我们执行的总时间将为5秒。

总结

如果我们在方法中有多个等待方法要执行,最好将它们作为Task,而不是等待一个。考虑对方法的执行顺序进行排序,以便我们可以为其他操作节省一些时间。

在本文中可能只有2秒钟,但在现实世界中,2秒钟是一段很长的时间,并且会存在性能问题。

或者,您可以使用Task.WhenAll方法来等待所有awaitable完成其操作。

感谢阅读!

© . All rights reserved.