当前位置 : 主页 > 编程语言 > c语言 >

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

来源:互联网 收集:自由互联 发布时间:2021-06-25
假设我有以下操作方法: [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");
}
网友评论