The most common issue I see with async programming is that the naive style seen in most samples/docs is strictly slower than standard imperative programming for one user . In other words, it's pure overhead with no benefit at all unless you're at a very large scale and approaching 100% capacity on your hosts. Most documentation -- and most code I've seen in the wild -- reads like this: var foo = await GetFooAsync(...…
var bar = await GetBarAsync(...);
var baz = await GetBazAsync(...);
Unfortunately this is the kind of example that is being used in the MS docs and elsewhere to explain async. I spent a long time figuring out what the difference was when they ran the exact same way as the synchronous version.