是否从Task<>;.Factory.StartNew/Task.Factory.ContinuteWhenAl

本文关键字:Factory Task StartNew ContinuteWhenAl gt lt 是否 | 更新日期: 2023-09-27 18:28:10

我有下面的简化代码,它异步地从多个运营商获得运费,我想知道是否值得转换为使用异步/等待方法,如果是,最好的方法是什么?或者,如果它现在运行良好,它真的不值得付出努力吗?非常感谢。

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
}

是否从Task<>;.Factory.StartNew/Task.Factory.ContinuteWhenAl

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

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

var tasks = new Task<ShippingRateCollection>[]
{
    GetUPSRatesAsync(),
    GetUSPSRatesAsync(),
    GetFedExRatesAsync()
};
ShippingRateCollection[] results = await Task.WhenAll(tasks);
// process results

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

我会考虑使用Microsoft的Reactive Framework来实现这一点。你可以使用这个代码:

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(...)方法将在结果可用时立即返回结果,而不是等待所有结果完成。

如果你真的想让他们完成,那么你可以这样更改代码:

query
    .ToArray()
    .Subscribe(rates =>
    {
        foreach (ShippingRate rate in rates)
        {
            //display rate
        }
    });

只需NuGet"Rx-Main"即可获得所需的位。

Jakub Lortz答案的一个不那么详细的版本:

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