我是异步世界中的新人。关于静态方法(来自https://stackoverflow.com/a/25733275/1596974):
static async Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks, TimeSpan timeout)
{
var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult));
var completedTasks =
(await Task.WhenAll(tasks.Select(task => Task.WhenAny(task, timeoutTask)))).
Where(task => task != timeoutTask);
return await Task.WhenAll(completedTasks);
}
我应该如何使用它来检索这些任务的结果? 为了清楚起见,我需要在这里实现的基本上是:
答案 0 :(得分:1)
对于那些失败的人,他们会抛出异常吗?或者他们只是挂了很长时间?
我可能会这样做:
var shippingProviderRateTasks = ...;
var results = ...;
foreach (var task in shippingProviderRateTasks) {
try {
results.Add(await task);
} catch (Exception e) {
// log the error here, if you want, and skip this provider
}
}
使用Task.WhenAll的主要原因之一是在发生异常时捕获异常,而不是稍后捕获异常。如果你想吞下所有异常并且基本上忽略这些错误,你也可以一次一个地等待它们 - 它不应该慢一些。
答案 1 :(得分:1)
好的,我最终得到了这个效果非常好的代码:
var providers = GetShippingProviders().ToList();
var tasks = new Task<Task>[providers.Count];
var timeout = TimeSpan.FromMilliseconds(10000);
try
{
var shippingRates = new List<IShippingRate>();
for (var i = 0; i < tasks.Length; i++)
{
var provider = providers[i];
tasks[i] = Task.WhenAny(Task.Run(() => provider.GetShippingRates(origin, destination, weight)), Task.Delay(timeout));
}
Task.WaitAll(tasks);
foreach (var tasksResult in tasks.Select(x => x.Result).Where(x => x.Status == TaskStatus.RanToCompletion))
{
var shippingRatesResult = tasksResult as Task<List<IShippingRate>>;
if (shippingRatesResult != null)
shippingRates.AddRange(shippingRatesResult.Result.ToList());
}
}
catch (AggregateException ae)
{
Log.Error("An exception occurred when retrieving the shipping Rates.", ae.Flatten());
}
处理完成的所有任务。失败的那些可以被跳过。有一种方法可以使用“Task.ContinueWith(...)”添加一些代码,因此可以捕获故障任务以记录异常。