Async Task.WhenAll with timeout - 完成任务累积的问题

时间:2014-09-07 22:26:21

标签: c# .net timeout task-parallel-library async-await

我创建了以下内容,以便在超时时执行多个异步任务。我正在寻找能够从任务中提取结果的东西 - 只需要那些超过超时的结果,无论其他任务是否未能完成(简化):

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. 任何想法如何避免这种积累?
  3. PS:请参阅我对this问题的回答。

1 个答案:

答案 0 :(得分:3)

我无法使用我的psychic debugging来理解为什么你的代码“导致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>>[]),这样就可以从这些任务中实际返回结果。< / LI>
  • await之后,我们需要过滤掉返回我们超时任务的WhenAny次调用,因为那里使用string.Empty没有结果(只有completedTasks.Where(task => task != timeoutTask))。< / LI>

P.S :我也answered that question我会(令人惊讶地)建议您使用我的解决方案。


注意:使用Task.Result属性isn't advisable。你应该await代替它(即使知道它已经完成