gpt4 book ai didi

c# - 不等待所有任务是否安全

转载 作者:行者123 更新时间:2023-11-30 14:21:36 24 4
gpt4 key购买 nike

假设我有以下操作方法:

[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()) 是确保所有任务成功完成所必需的吗? Result not 未被 Exists 访问的任务是否会在后台成功完成执行?或者是否有可能因为某些任务(未等待)被丢弃,因为它们不会附加到请求中?我是否缺少更好的实现方式?

最佳答案

在您提供的实现下,Task.WaitAll 调用会阻塞调用线程,直到所有 任务完成。它只会继续下一行并在发生这种情况后执行 Exists 检查。如果删除 Task.WaitAll,则 Exists 检查将导致调用线程按顺序阻塞每个任务;即它首先在 tasks[0] 上阻塞;如果这返回 false,那么它将阻塞 tasks[1],然后是 tasks[2],依此类推。这是不可取的,因为如果任务无序完成,它不允许您的方法提前完成。

如果您只需要等到哪个任务首先返回 true,那么您可以使用 Task.WhenAny。这将使您的异步方法在任何 任务完成后立即恢复。然后您可以检查它是否评估为真并立即返回成功;否则,您将继续对剩余的任务集合重复该过程,直到没有任务为止。

如果您的代码作为应用程序(WPF、WinForms、控制台)运行,则其余任务将继续在线程池上运行直到完成,除非应用程序已关闭。线程池线程是后台线程,因此如果所有前台线程都已终止(例如,因为所有窗口都已关闭),它们将不会使进程保持事件状态。

由于您运行的是网络应用程序,因此您会面临在任务完成之前回收应用程序池的风险。未等待的任务是即发即弃的,因此不会被运行时跟踪。为防止这种情况发生,您可以通过 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");
}

关于c# - 不等待所有任务是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54137513/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com