繁体   English   中英

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

[英]Async Task.WhenAll with timeout - issue with completed tasks accumulating

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

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:请参阅我对这个问题的回答。

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

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


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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM