2017-08-25 64 views
1

我是异步世界中的新成员。关于你提到的静态方法(从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); 
} 

我应该如何使用它,以便检索这些任务的结果? 只是要清楚,我需要在这里实现基本上是这样的:

  • 对于我打电话给几家船供应商,以便从他们那里得到不同的运费每一项任务。
  • 将来自所有运输供应商的响应汇总到一个大的运费清单中。 有时一个(或多个)运输供应商可能停运。因此,我需要从已成功完成的任务中检索运费,然后跳过那些失败的任务。 我希望我很清楚。

回答

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

好吧,我结束了这段代码中工作得很好:

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(...)”添加一些代码,这样可以抓住故障任务以记录异常。