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

标签 c# .net asp.net-core async-await

假设我有以下操作方法:

[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/

相关文章:

c# web api post 请求 null

c# - 通过仅显示特定字段来格式化 JSON 输出

c# - 使用 Web API 过滤

c# - 从 Microsoft UWP 上的异步方法返回 Task<string>

c# - 跨平台 C# 媒体 API

.net - 未处理的异常:System.Configuration.ConfigurationErrorsException:无法识别的元素“服务”。嵌套ConfigurationElementCollection

.net - ODBC 连接池

c# - 使用确切的字符数进行表单验证

c# - 将(字符串,多维数组)的对象转换为 C# Dotnet 5.0 中的 JSON 结果

c# - 在 ASP.NET 中轮询 Google Big Query 结果期间调用 Thread.Sleep 是否合适?备择方案?