How would I go about writing an async controller action that is made up of 1 +n async calls (await)? E.g. let's pretend I need to retrieve the object Foo first and it has a variable number of Bars identifier and I need to fetch all those entities (for the sake of this question, there is no fetchBarsByFooId. Would I use Task.WaitAll or maybe Parallel.For?
public async Task<ActionResult> Bars(int id) {
Foo foo = await this.FooProvider.GetFooAsync(id);
var bars = new ConcurrentQueue<Bar>();
// Sub-optimal version
foreach (int barId in foo.BarIDs) {
Bar bar = this.BarProvider.GetBar(barId);
bars.Enqueue(bar)
}
// Fetch each bar asynchronously and pass them to the view.
....
return View(bars.ToArray());
}
Well, the first thing to work out is whether you actually want parallelism, or just asynchrony. Just asynchrony is simple:
var bars = new List<Bar>();
foreach (var id in foo.Bars)
{
bars.Add(await BarProvider.GetBarAsync(id));
}
return View(bars);
For parallelism, you could use Task.WhenAll:
var tasks = foo.Bars.Select(id => BarProvider.GetBarAsync(id));
var bars = await Task.WhenAll(tasks);
return View(bars);
(I realize this is shorter code than the non-parallel version - but it's more conceptually tricky.)
You should not use Parallel.For or Task.WaitAll as both of those are blocking calls - whereas Task.WhenAll returns you a task which will complete when all the subtasks have completed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With