首页 > 解决方案 > async & await - 如何等到所有任务完成?

问题描述

好的。我制作了一个简单的控制台应用程序来弄清楚如何使所有这些工作。一旦我有了基本的大纲,我就会将它应用到实际的应用程序中。

这个想法是我们有很多数据库调用要执行,我们知道这些调用需要很长时间。我们不想(或必须)等待一个数据库调用完成,然后再进行下一次调用。它们都可以同时运行。

但是,在进行所有调用之前,我们需要执行“开始”任务。而当所有的调用都完成后,我们需要执行一个“完成”的任务。

这是我现在的位置:

static void Main(string[] args)
{
    Console.WriteLine("starting");
    PrintAsync().Wait();        
    Console.WriteLine("ending");  // Must not fire until all tasks are finished
    Console.Read();
}

// Missing an "await", I know. But what do I await for?
static async Task PrintAsync()
{
    Task.Run(() => PrintOne());
    Task.Run(() => PrintTwo());
}

static void PrintOne()
{
    Console.WriteLine("one - start");
    Thread.Sleep(3000);
    Console.WriteLine("one - finish");
}

static void PrintTwo()
{
    Console.WriteLine("two - start");
    Thread.Sleep(3000);
    Console.WriteLine("two - finish");
}

但无论我尝试什么,Ending总是过早地打印出来:

starting
ending
one - start
two - start
one - finish
two - finish

正确的工作是在完成PrintTwo()之前开始PrintOne()。但是在做任何其他事情之前,我该如何正确地等待PrintAsync()完成呢?

标签: c#.netmultithreadingasynchronousasync-await

解决方案


您需要等待内部任务的结束:

static async Task PrintAsync()
{
    await Task.WhenAll(Task.Run(() => PrintOne()), Task.Run(() => PrintTwo()));
}

解释:async Task表示一个等待的方法。在此方法中,您还可以使用awaitTasks。如果您不这样做,那么它只会让任务松散,这些任务将自行运行。Task.Run返回一个Task可以等待的。如果您希望两个任务并行运行,您可以使用返回值中的任务并在等待方法Task.WhenAll中使用它们

编辑:实际上 Visual Studio 会用绿色曲线标记此代码。将鼠标悬停在其上时,您会收到警告:

在此处输入图像描述

CS4014

这应该解释为什么"ending"在任务完成之前打印

编辑2:

如果您有一组要迭代的参数并调用异步方法来传递参数,您也可以使用 1 行中的 select 语句来完成:

static async Task DatabaseCallsAsync()
{
    // List of input parameters
    List<int> inputParameters = new List<int> {1,2,3,4,5};  
    await Task.WhenAll(inputParameters.Select(x => DatabaseCallAsync($"Task {x}")));
}

static async Task DatabaseCallAsync(string taskName)
{
    Console.WriteLine($"{taskName}: start");
    await Task.Delay(3000);
    Console.WriteLine($"{taskName}: finish");
}

最后一部分与上一个答案相似


推荐阅读