【问题标题】:Async Task.WhenAll with timeout - issue with completed tasks accumulatingAsync Task.WhenAll 超时 - 已完成任务累积的问题
【发布时间】:2014-11-01 03:30:16
【问题描述】:

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

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. 知道如何避免这种积累吗?

PS:见我对this问题的回答。

【问题讨论】:

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


【解决方案1】:

我无法使用我的 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&lt;string&gt; 而不是 Task
  • 这使得每个WhenAny 调用也返回一个Task&lt;string&gt;(并且tasksOfTasksTask&lt;Task&lt;string&gt;&gt;[]),这使得实际上可以从这些任务中返回一个结果。
  • awaiting 之后,我们需要过滤掉返回超时任务的WhenAny 调用,因为使用completedTasks.Where(task =&gt; task != timeoutTask) 不会有结果(只有string.Empty)。

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


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

【讨论】:

  • 谢谢。我进行了许多测试并意识到当我使用上面的初始化程序初始化 tasksOfTasks 时,一切都很顺利,但是当我动态创建集合时(例如,通过使用 LINQ 查询到 IEnumerable&lt;Task&lt;MyResult&gt;&gt;) - 我需要这样做,任务又开始积累了。可悲的是,当我尝试动态初始化上面的示例时,它仍然运行良好,这意味着它可能是我的代码中的其他复杂性(这当然比我在这里展示的更复杂)。
猜你喜欢
  • 1970-01-01
  • 2015-05-21
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多