.NET Core 2.2,VS 2019
问题是UpdateDatabaseWithFile
从未执行过?我在这里做错了什么?我试图用等待包装Directory
,但是我不能,因为它返回void。正确的方法是什么?
代码如下:
Directory
.GetFiles(@"C:\Temp")
.ToList()
.ForEach(async file =>
{
await this._dataService.UpdateDatabaseWithFile();
});
答案 0 :(得分:5)
这是因为ForEach<T>
仅执行了async
个函数,而没有等待它们完成。
您可以使用Select
投影必须执行的任务,然后使用Task.WhenAll()
执行该功能并等待其完成:
var tasks = Directory
.GetFiles(@"C:\Temp")
.Select(async file =>
{
await this._dataService.UpdateDatabaseWithFile();
});
await Task.WhenAll(tasks);
或者,如果要顺序执行函数,则可以使用简单的Task.WhenAll()
代替foreach
:
foreach (var file in Directory.GetFiles(@"C:\Temp"))
{
await this._dataService.UpdateDatabaseWithFile();
}
其他说明:
Here是ForEach<T>
的实现:
for(int i = 0 ; i < array.Length; i++) {
action(array[i]);
}
如您所见,它只是执行该操作,而没有等待其完成。实际上,它不能。 Action
不返回任何内容。但是必须等待Task
返回。因此,为了使ForEach
函数在这种情况下有用,必须使用Func
并返回Task
,然后在for
迭代器中等待。.
答案 1 :(得分:1)
方法List.ForEach
不理解异步委托,换句话说,它没有接受Func<Task<T>>
参数的重载。在这些情况下,发生的情况是将提供的异步lambda视为async void
。 Async voids are evil,因为无法等待它们,所以它们的执行无法与程序的其他部分协调。它们类似于“一劳永逸”的任务,但有一个额外的缺点,即在发生异常情况时终止进程。
返回无效的异步方法有一个特定目的:使异步事件处理程序成为可能。
您应注意尝试使用异步委托作为参数调用的方法的签名。诸如Task.Run
之类的某些方法对异步委托具有特定的重载,并能很好地处理它们。诸如LINQ Select
之类的其他方法在设计时并未考虑异步等待,但至少它们接受类型为Func
而不是Action
的参数,因此将返回生成的任务,并且可以收集并正确等待。带有List.ForEach
参数的Action
之类的方法永远不能与异步委托一起使用。
答案 2 :(得分:-2)
这里最可能的问题是.ForEach()
无法让您真正等待操作完成。它将执行它们并继续前进。
埃里克·利珀特(Eric Lippert)提出了a good blog post来说明为什么.ForEach()
方法并不那么出色,这是foreach
循环优于.ForEach
的一个完美示例- foreach
将允许您实际等待操作。
只需使用循环,问题就会消失:
foreach (var file = Directory.GetFiles(@"C:\Temp"))
{
await this._dataService.UpdateDatabaseWithFile();
}
应该注意,您似乎实际上并没有在任何地方使用file
变量,这似乎是一个问题。希望只是一个错字?