异步任务.WhenAll超时-已完成任务累积的问题



我创建了以下内容,以便在超时的情况下执行多个异步任务。我正在寻找一种可以从任务中提取结果的方法——只提取那些超过超时的结果,而不管其他任务是否失败(简化):

TimeSpan timeout = TimeSpan.FromSeconds(5.0);
Task<Task>[] tasksOfTasks =
{
    Task.WhenAny(SomeTaskAsync("a"), Task.Delay(timeout)),
    Task.WhenAny(SomeTaskAsync("b"), Task.Delay(timeout)),
    Task.WhenAny(SomeTaskAsync("c"), Task.Delay(timeout))
};
Task[] completedTasks = await Task.WhenAll(tasksOfTasks);
List<MyResult> = completedTasks.OfType<Task<MyResult>>().Select(task => task.Result).ToList();

我已经在(Web API)服务器中的一个非静态类中实现了这一点。

这在第一次调用中运行良好,但是额外的调用导致completedTasks奇怪地累积了以前对服务器的调用中的任务(如调试器所示)。在第二次通话中,有6项任务已完成,在第三次通话中有9项任务,依此类推

我的问题:

  1. 知道为什么吗?我想这是因为以前的任务没有被取消,但这段代码在一个类的新实例中
  2. 知道如何避免这种积累吗

附言:请参阅我对此问题的回答。

我无法使用我的心理调试来理解为什么您的代码"导致completedTasks从以前的调用中奇怪地累积任务",但它可能暴露了您的一些误解。

下面是一个基于代码的工作示例(使用string而不是MyResult):

Task<string> timeoutTask = 
    Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(_ => string.Empty);
Task<Task<string>>[] tasksOfTasks =
{
    Task.WhenAny(SomeTaskAsync("a"), timeoutTask),
    Task.WhenAny(SomeTaskAsync("b"), timeoutTask),
    Task.WhenAny(SomeTaskAsync("c"), timeoutTask)
};
Task<string>[] completedTasks = await Task.WhenAll(tasksOfTasks);
List<string> results = completedTasks.Where(task => task != timeoutTask).
    Select(task => task.Result).ToList();

那么,不同之处在于:

  • 我对所有WhenAny调用使用相同的超时任务。没有必要使用更多,它们可以在稍微不同的时间内完成
  • 我让超时任务返回一个值,所以它实际上是Task<string>,而不是Task
  • 这使得每个WhenAny调用也返回一个Task<string>(并且tasksOfTasksTask<Task<string>>[]),这将使得实际返回这些任务的结果成为可能
  • awaiting之后,我们需要过滤掉返回超时任务的WhenAny调用,因为使用completedTasks.Where(task => task != timeoutTask)不会有结果(只有string.Empty

p.S:我也回答了这个问题,我会(令人惊讶地)建议您使用我的解决方案。


注意:不建议使用Task.Result属性。您应该await它(即使您知道它已经完成

相关内容

  • 没有找到相关文章

最新更新