c# - 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()
完成呢?
解决方案
您需要等待内部任务的结束:
static async Task PrintAsync()
{
await Task.WhenAll(Task.Run(() => PrintOne()), Task.Run(() => PrintTwo()));
}
解释:async Task
表示一个等待的方法。在此方法中,您还可以使用await
Tasks。如果您不这样做,那么它只会让任务松散,这些任务将自行运行。Task.Run
返回一个Task
可以等待的。如果您希望两个任务并行运行,您可以使用返回值中的任务并在等待方法Task.WhenAll中使用它们
编辑:实际上 Visual Studio 会用绿色曲线标记此代码。将鼠标悬停在其上时,您会收到警告:
这应该解释为什么"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");
}
最后一部分与上一个答案相似
推荐阅读
- r - R中是否有一种简单的方法可以访问向量中负元素的位置?
- c# - 如何在 Xamarin Forms 中使用 Prism MVVM 和 ContentView?
- android - 如何使用 URL 创建字符串
- python - numpy.concatencate 两个相同大小的行向量到矩阵
- python - 从熊猫数据框列中的字典列表中获取第一个值
- sql - 替换查询sql postgresql中的AZ和0-9
- google-apps-script - FormSubmit = e.range的已安装触发器无法调用未定义的GetRowIndex方法?
- django - 如何从列表模板访问 Django 2 中的详细信息模板?
- typescript - “接口中的计算属性名称必须直接引用内置符号”
- python - 从持续时间中查找平均值,但同一天的日志为一个