是否从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
}
如果可以使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());