I’ve talked about async best practices a lot, and each time I’ve tried to refine the talk a little further. Here’s the best I can explain how to use async effectively!
- online videos on Channel9
- slides.pptx [6.1mb]
- source code.zip [430k, some in VB requires VS2012+Windows8 or higher, some in C# requires VS2013 or higher]
- transcript.docx [43k]
1. For goodness’ sake, stop using async void. Async void is for top-level event-handlers, and event-handler like things. I see too many people using it elsewhere in their code where they shouldn’t. Please stop.
2. Use async for IO-bound tasks, and threadpool for CPU-bound tasks. Use async only for disk and IO bound stuff. Use the threadpool (Task.Run, Parallel.For, LINQ AsParallel) only for CPU-bound stuff. If you get this wrong, then your server code won’t scale.
3. Use TaskCompletionSource to wrap events up into Tasks. Event-based programming with callbacks and lambdas are hard, and you must learn how to use TaskCompletionSource to tame them.
4. Libraries shouldn’t lie. The threadpool is an app-global resource, so you should leave the callers of your library to decide how and when they want to use it. Your library methods should not use the threadpool (Task.Run, Parallel.For, …) internally in secret. They should have async signatures if and only if their internal implementations are truly async.
5. Libraries should have chunky async APIs. But if you can’t, there’s a micro-optimization you can use for async methods based around the fast-path which can reduce or eliminate the heap overhead of async methods. Only consider this micro-optimization after profiling your app, of course.
6. Libraries should consider Task.ConfigureAwait(false). There’s another micro-optimization you can use to reduce your methods’ impact on the UI thread. Consider this if your library routine might be called from the UI thread, and has chatty awaits inside it. This technique is used throughout the .NET Framework because it also avoids deadlock in certain poor-practice user code.
Earlier version. At the 2013 MVP summit R2 in Redmond, I gave a talk on “Async Best Practices”. This talk was largely a condensed version of two earlier talks, [here], which also have video-recordings. But in case anyone wants the slides from the MVP-summit-version, here they are:
- Slides.pptx [6.2mb]
- Source code.zip [440k, some in VB requires VS2012 on Windows8, some in C# requires VS2012/2013]
- Speaker notes.docx [41k, a complete transcript of what I said]
We also held three hours of “Async Clinic”, where people could come with their questions. Other experts in the room were Stephen Cleary MVP, and Stephen Toub, Mads Torgersen and Alex Turner. I took notes as we went. These notes are in very rough form. I hope to revise them into something more useful.
- Slides.pptx [126k]
- Raw notes.txt [10k]
- pod7.vb [69k, VB, requires VS2010 or higher running on Mono or Windows]
The last piece of code “pod7.vb” relates to a question that was asked. Someone wanted to write an app which did a lot of web-scraping, then processing the results. To architect this, I recommend keeping a queue of workitems for each step along the pipeline. Then you can have a worker, either a synchronous method on a thread or just an asynchronous method, whose job is to retrieve items from the queue and process them and dump them into the next queue. This way you can have diagnostics that show what’s doing what. Anyway, I wrote this code to scrape a website (IO-bound), stream down audio (IO-bound), expand it to PCM (disk-bound), compress it to MP3 (cpu-bound). It’s not best-practice code, and it doesn’t demonstrate Async at all, but it does demonstrate queues and workers and scraping.