The 50ms Rule

This is the rule that Microsoft followed with the WinRT APIs; anything taking less than 50ms is considered “fast” and close enough to “immediate” that they do not require an asynchronous API. I also recommend this rule be applied to any synchronous blocks of code; if they are likely to take more than 50ms, push them onto the thread pool via Task.Run.

The Hundred Continuations Per Second Rule

It’s usually a good idea to use ConfigureAwait(false) in your library code, and only run continuations on the UI thread if they actually need a UI context. But how many continuations can the UI thread really be expected to handle?

At least on the WinRT platform, “the guidance is that just a hundred or so awaits resuming on the UI thread per second will be fine, but a thousand per second will be bad” (Lucian Wischik, Async Design Patterns). Naturally, this is assuming that the continuations do not block for any substantial period of time.

Caveats

It’s difficult to lay down any kind of firm guidance. It’s easy to have a situation where the 4-core 8-GB developer’s machine handles a thousand continuations on the UI thread easily, but that old XP laptop your client has isn’t going to hack it. With WinRT, the hardware is at least somewhat constrained, so the above rules have a stronger meaning on that platform. In the real world, you’ll have to test with realistic clients and derive your own numbers.