Reputation: 21
I have the simplified code below that gets shipping rates from multiple carriers asynchronously and was wondering if it would be worthwhile to convert to using an async/await methodology instead and if so what the best approach would be to go about doing that? Or if its working okay now is it really not worth the effort? Thank you.
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
}
Upvotes: 1
Views: 182
Reputation: 14846
A less verbose version of Jakub Lortz's answer:
var results = await Task.WhenAll(
GetUPSRatesAsync(),
GetUSPSRatesAsync(),
GetFedExRatesAsync());
Upvotes: 0
Reputation: 117064
I would look at using Microsoft's Reactive Framework for this. You can use this code:
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
});
The code runs asynchronously and the .Subscribe(...)
method will return results as soon as they are available rather than waiting for all of them to finish.
If you do want them to finish then you can change the code like this:
query
.ToArray()
.Subscribe(rates =>
{
foreach (ShippingRate rate in rates)
{
//display rate
}
});
Just NuGet "Rx-Main" to get the required bits.
Upvotes: 1
Reputation: 14896
You should definitely refactor it to async
/await
if you can make the Get*Rates
methods asynchronous. In your current code you execute them on separate threads only to block the threads waiting for I/O to complete. That's a waste.
If you can make these methods asynchronous, the code might look like this:
var tasks = new Task<ShippingRateCollection>[]
{
GetUPSRatesAsync(),
GetUSPSRatesAsync(),
GetFedExRatesAsync()
};
ShippingRateCollection[] results = await Task.WhenAll(tasks);
// process results
Even if you have to work with synchronous GetRates
methods, refactoring the code to async
/await
will simplify it.
Upvotes: 2