[英]async & await - How to wait until all Tasks are done?
好。 我制作了一个简单的控制台应用程序,以弄清楚如何完成所有这些工作。 一旦基本轮廓开始工作,然后将其应用于实际应用程序。
这个想法是,我们要执行很多数据库调用,这将花费很长时间。 我们不想(或不必)等待一个数据库调用完成之后再进行下一个。 它们可以同时运行。
但是,在进行所有调用之前,我们需要执行“启动”任务。 当所有调用完成后,我们需要执行“完成”任务。
这是我现在的位置:
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
IS的正确工作是在完成PrintTwo()
之前启动PrintOne()
。 但是,在执行其他操作之前,如何正确等待PrintAsync()
完成?
您需要等待内部任务的结束:
static async Task PrintAsync()
{
await Task.WhenAll(Task.Run(() => PrintOne()), Task.Run(() => PrintTwo()));
}
说明: async Task
表示一个等待的方法。 在此方法内,您还可以await
任务。 如果您不这样做,那么它将简单地让任务松散,这些任务将自行运行。 Task.Run
返回可以等待的Task
。 如果你想两个任务并行运行,你可以从retur值使用的任务,并在awaitable方法使用它们Task.WhenAll
编辑:实际上,Visual Studio会用绿色弯曲线标记此代码。 当将鼠标悬停在上面时,您会得到警告:
这应该可以解释为什么在任务完成之前打印"ending"
编辑2:
如果您有要迭代的参数集合并调用异步方法以传递参数,则也可以在第一行中使用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");
}
最后一部分类似于上一个答案
在这里操作。 我将Mong Zhu的答案标记为正确,因为它可以将我引向解决方案。 但我也想在这里分享最终结果,包括juharr的评论中的出色反馈。 这是我想出的:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("starting");
DatabaseCallsAsync().Wait();
Console.WriteLine("ending"); // Must not fire until all database calls are complete.
Console.Read();
}
static async Task DatabaseCallsAsync()
{
// This is one way to do it...
var tasks = new List<Task>();
for (int i = 0; i < 3; i++)
{
tasks.Add(DatabaseCallAsync($"Task {i}"));
}
await Task.WhenAll(tasks.ToArray());
// This is another. Same result...
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");
}
}
结果如下:
starting
Task 0: start
Task 1: start
Task 2: start
Task 2: finish
Task 0: finish
Task 1: finish
ending
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.