[英]Is it safe not to wait for all tasks
假设我有以下操作方法:
[HttpPost]
public async Task<IActionResult> PostCall()
{
var tasks = new List<Task<bool>>();
for (int i = 0; i < 10; i++)
tasks.Add(Manager.SomeMethodAsync(i));
// Is this line necessary to ensure that all tasks will finish successfully?
Task.WaitAll(tasks.ToArray());
if (tasks.Exists(x => x.Result))
return new ObjectResult("At least one task returned true");
else
return new ObjectResult("No tasks returned true");
}
Task.WaitAll(tasks.ToArray())
必须确保所有任务都能成功完成? Exists
无法访问其Result
的任务是否会成功完成后台执行? 或者有些任务(没有等待)会被删除,因为它们不会附加到请求中吗? 有没有更好的实施我错过了?
是的,除非等待它们(等待等待的东西),否则不保证任务完成
在您的情况下,您应该进行的主要更改是创建Task.WaitAll
await Task.WhenAll(tasks);
所以它实际上是异步的。 如果你只是想等待一个任务返回,使用WhenAny
代替。
在您提供的实现下, Task.WaitAll
调用阻止调用线程,直到所有任务都完成。 它只会进入下一行,并在发生这种情况后执行Exists
检查。 如果删除Task.WaitAll
,则Exists
检查将导致调用线程按顺序阻塞每个任务; 即它首先阻止tasks[0]
; 如果返回false,则会阻塞tasks[1]
,然后阻塞tasks[2]
,依此类推。 这是不可取的,因为如果任务完成无序,它不允许您的方法提前完成。
如果您只需要等到任何一个任务首先返回true,那么您可以使用Task.WhenAny
。 这将使任何任务完成后您的异步方法恢复。 然后,您可以检查它是否评估为true并立即返回成功; 否则,您将继续重复剩余任务集的过程,直到没有剩余任务为止。
如果您的代码作为应用程序(WPF,WinForms,Console)运行,那么剩余的任务将继续在线程池上运行直到完成,除非应用程序关闭。 线程池线程是后台线程,因此如果所有前台线程都已终止(例如因为所有窗口都已关闭),它们将不会使进程保持活动状态。
由于您运行的是Web应用程序,因此您可能会在任务完成之前回收应用程序池。 未完成的任务是即发即弃的,因此运行时未被跟踪。 为了防止这种情况发生,您可以通过HostingEnvironment.QueueBackgroundWorkItem
方法在运行时注册它们,如注释中所示。
[HttpPost]
public async Task<IActionResult> PostCall()
{
var tasks = Enumerable
.Range(0, 10)
.Select(Manager.SomeMethodAsync)
.ToList();
foreach (var task in tasks)
HostingEnvironment.QueueBackgroundWorkItem(_ => task);
while (tasks.Any())
{
var readyTask = await Task.WhenAny(tasks);
tasks.Remove(readyTask);
if (await readyTask)
return new ObjectResult("At least one task returned true");
}
return new ObjectResult("No tasks returned true");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.