假设我有以下操作方法: [HttpPost]public async TaskIActionResult PostCall(){ var tasks = new ListTaskbool(); for (int i = 0; i 10; i++) tasks.Add(Manager.SomeMethodAsync(i)); // Is this line necessary to ensure that all tasks will
[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调用阻止调用线程,直到所有任务都完成.它只会进入下一行,并在发生这种情况后执行Exists检查.如果删除Task.WaitAll,则Exists检查将导致调用线程按顺序阻塞每个任务;即它首先阻止任务[0];如果返回false,则会阻塞任务[1],然后阻塞任务[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"); }