Parallel Work in Async MVC Actions

Wednesday, June 20, 2012

One of the samples in the ASP.NET MVC 4 release notes is an example of using an async controller action.

public async Task<ActionResult> Index(string city)
{
var newsService = new NewsService();
var sportsService = new SportsService();

return View("Common",
new PortalViewModel
{
NewsHeadlines = await newsService.GetHeadlinesAsync(),
SportsScores = await sportsService.GetScoresAsync()
});
}

At first glance, it might seem like getting the headlines and getting the sports scores are two operations that happen in parallel, but the way the code is structured this can’t happen. It’s easier to see if you add some async methods to the controller and watch the different threads at work in the debugger.

public async Task<ActionResult> Index(string city)
{
return View("Common",
new PortalViewModel
{
NewsHeadlines = await GetHeadlinesAsync(),
SportsScores = await GetScoresAsync()
});
}
async Task<IEnumerable<Score>> GetScoresAsync()
{
await Task.Delay(3000);
// return some scores ...
}

async Task<IEnumerable<Headline>> GetHeadlinesAsync()
{
await Task.Delay(3000);
// return some news
}

In the methods I’ve introduced a delay using Task.Delay (which returns a Task you can await and thereby free the calling thread, unlike Thread.Sleep which will block). The total time to render the view will be at least 6,000 milliseconds, because the Index action awaits the result of GetHeadlinesAsync. Awating will suspend execution before GetScoresAsync has a chance to start.
If you want the headlines and scores to work in parallel, you can kick off both async calls before awaiting the first result.
public async Task<ActionResult> Index(string city)
{
var newsService = new NewsService();
var sportsService = new SportsService();

var newsTask = newsService.GetHeadlinesAsync();
var sportsTask = sportsService.GetScoresAsync();

return View("Common",
new PortalViewModel
{

NewsHeadlines = await newsTask,
SportsScores = await sportsTask
});
}

Comments
gravatar Filip Wednesday, June 20, 2012
This is a great insight, thanks a lot.
gravatar Nikola Malovic Wednesday, June 20, 2012
Another way to acheive this is Task.WaitAll(newsTask, sportsTask) which is not awaiting in sequence and has better exception handling
gravatar scott Wednesday, June 20, 2012
@Nikola: Did you mean WhenAll? WaitAll blocks, so I don't think it is a good candidate for an async method.
gravatar Rick Anderson Wednesday, June 20, 2012
My tutorial www.asp.net/... shows all this in great detail
gravatar Rick Anderson Wednesday, June 20, 2012
More elegantly (copied from my tutorial)
await Task.WhenAll(widgetTask, prodTask, gizmoTask);
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!