Now that it’s easy in c#, I’m a big fan of asynchronous and parallel programming. You can make multi-step code go multiple times faster, and prevent the evil .NET ThreadPool from blocking and throttling your code all in one step.
Although there is some great performance advice in articles such as MSDN’s Async Performance: Understanding the Costs of Async and Await, I’d like to go a little deeper on some rationale on when to use async and when not to use async.
The best thing to do is to prototype your solution and do performance testing, but if you don’t have time to do that, then these guidelines might help you make a decision. (If you have something to add, or dispute some of the logic, please comment at the end.)
Generally, if you are writing NEW code, the choice is pretty simple:
- If you are making a .NET API call that ends in Async, you PROBABLY SHOULD use async.
- If you can do things in parallel, you SHOULD use the Task Parallel Library or async code to do more things at a time.
- If you have a main UI, ASP, or Service thread that can go do work for someone else while you are doing CPU work or waiting, you PROBABLY SHOULD use async.
- Otherwise, you PROBABLY SHOULD NOT bother.
If rules 1-3 somewhat apply, but you are still on the fence, then try this rule to help you out:
- If your team is comfortable writing, reading and debugging async code, go ahead. The tools are good enough now, that the overhead is probably worth it. Otherwise, don’t bother.
Some cases for async are easy:
- Web Service calls – particularly if you have no idea how long they are going to take
- Database calls – particularly if they could take a long time
- Parallelism – doing more than one thing at a time
- CPU-bound tasks – moving them to a background thread
Some cases against async are easy:
- Short calculations or quick-running methods, e.g. writing to the Console for logging
- Synchronized Contexts
- It’s a good idea to move long-running work off your UI thread or other context-bound thread,
- but be careful about frequent context switching. See Potential Pitfalls in Data and Task Parallelism for a good discussion.
So that leaves us with the fuzzy area to discuss. I have a scenario where making the code asynchronous would make the code cleaner and more maintainable. In this case:
- there is EXISTING code
- calling a DATABASE
- but the queries SHOULD BE QUICK
- and there isn’t much else to do
Async or not async?
I put a lot of thought on this borderline case. My rationale is as follows:
- There isn’t anything to do in parallel
- The rest of the service is hitting the SAME database with the SAME queries, so serving another request probably won’t have much benefit
- There is a SINGLE database behind the service, so we wouldn’t benefit from querying other resources while waiting
- The performance for sync/async was about the same in benchmarks.
- The existing code works.
There isn’t a performance benefit for going async here. If this was NEW code, I would probably write it asynchronously (because it’s easy now) to get the benefit of eventually calling different services or databases. But this is existing working code, so I need a bigger benefit than just cleaner code. The aha moment for me here was that service is calling the same backend resource for the same queries, so the bottleneck isn’t at this layer. There’s no point in optimizing code that isn’t the bottleneck.