Mindful Parallelism in Async/Await

03 April 2017 - .NET

At our most recent .NET Oxford event, we had Frans Lytzen, founder and CTO of New Orbit talking about Async/Await in .NET.

Rather than just your typical "How to use Async/Await" talk - Frans' talk instead focused more on what happens under the hood - eg. timings and threads, and the reasons you get the deadlock situation. Straight away I felt I was learning new things from his talk.

However, the biggest day-to-day takeaway I took from his talk though was from his following slide ...


It took me quite a few seconds of looking at this thinking: what's the point in that... oh hang on... oh!... OH!... OF COURSE!!!

Now I just feel really dumb

It's actually really obvious when you think about it. I guess I tend to automatically "await all the things", and hadn't thought too much about the fact that each await causes my code to always run sequentially, even when it didn't need to do so!

In the case of a ASP.NET, I realised that I've only really been using async/await to allow ASP.NET to run more concurrent requests. Or in the case of a Windows app, I've been using it to stop the UI from blocking. Both really great benefits of async/await, but I haven't really been benefiting from it in my own code.

In-fact, I'm in the middle of rewriting my blog website (more on that soon!), and I've literally just seen a piece of my own code which was doing this ...

var posts = await _blogPostRepository.GetPagedAsync(offset, postsPerPage, ct);
var featured = await _blogPostRepository.GetFeaturedAsync(ct);
var recent = await _blogPostRepository.GetRecentAsync(ct);

Where the implementation of IBlogPostRepository queries SQL Server. I can't believe it hadn't occurred to me before that if I had just written this code like this ...

var postsTask = _blogPostRepository.GetPagedAsync(offset, postsPerPage, ct);
var featuredTask = _blogPostRepository.GetFeaturedAsync(ct);
var recentTask = _blogPostRepository.GetRecentAsync(ct);

var posts = await postsTask;
var featured = await featuredTask;
var recent = await recentTask;

... then it would have fired off those three queries asynchronously, rather than each one waiting for the previous one to complete before starting.

This really does demonstrate how complex parallelism can be made really easy using async/await.

I feel less dumb because I know it's not just me who does this. I actually see this all the time! This is definitely something I'm going to start paying much more attention too, both in my own code, and in code reviews.

Thanks again to Frans for his talk, and making me realize this silly thing I'd been doing. The full set of slides from his talk can be found on GitHub here.