是否从Task<> .Factory.StartNew / Task.Factory.ContinueWhenAll()转换为async / await?

时间:2015-12-24 22:58:44

标签: c# asynchronous async-await

我有以下简化代码,可以异步获取多个运营商的运费,并且想知道是否值得转换为使用异步/等待方法,如果是这样,那么最好的方法是做什么呢?或者,如果现在工作正常,那真的不值得努力吗?谢谢。

List<Task<ShippingRateCollection>> lstTasks = new List<Task<ShippingRateCollection>>();
Task<ShippingRateCollection> t;

t = Task<ShippingRateCollection>.Factory.StartNew(() => { return GetUPSRates(...); });
lstTasks.Add(t);

t = Task<ShippingRateCollection>.Factory.StartNew(() => { return GetUSPSRates(...); });
lstTasks.Add(t);

t = Task<ShippingRateCollection>.Factory.StartNew(() => { return GetFedExRates(...); });
lstTasks.Add(t);

//wait until all requests complete (or error out)
Task.Factory.ContinueWhenAll(lstTasks.ToArray(), (tasks) =>
{
    //wrap all exceptions into 1 AggregateException
    Task.WaitAll(tasks);
});

foreach (Task<ShippingRateCollection> task in lstTasks)
{
    foreach (ShippingRate rate in task.Result)
    {
        ... //display rate
    }   //next returned rate
}

3 个答案:

答案 0 :(得分:2)

如果可以使async方法异步,则应该将其重构为await / Get*Rates。在当前代码中,您只能在单独的线程上执行它们,以阻止等待I / O完成的线程。那是浪费。

如果可以使这些方法异步,代码可能如下所示:

var tasks = new Task<ShippingRateCollection>[]
{
    GetUPSRatesAsync(),
    GetUSPSRatesAsync(),
    GetFedExRatesAsync()
};

ShippingRateCollection[] results = await Task.WhenAll(tasks);

// process results

即使您必须使用同步GetRates方法,将代码重构为async / await也会简化它。

答案 1 :(得分:1)

我会考虑使用Microsoft的Reactive Framework。您可以使用以下代码:

public $incrementing = false;

代码以异步方式运行,var fs = new Func<ShippingRateCollection>[] { () => GetUPSRates(...), () => GetUSPSRates(...), () => GetFedExRates(...), }; var query = from f in fs.ToObservable() from rate in Observable.Start(f) select rate; query .Subscribe(rate => { //display rate }); 方法会在结果可用时立即返回结果,而不是等待所有结果完成。

如果您确实希望它们完成,那么您可以更改代码:

.Subscribe(...)

Just NuGet&#34; Rx-Main&#34;得到所需的位。

答案 2 :(得分:0)

Jakub Lortz答案的详细版本:

var results = await Task.WhenAll(
    GetUPSRatesAsync(),
    GetUSPSRatesAsync(),
    GetFedExRatesAsync());