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(...);
The timeline of that code is exactly same as the standard synchronous version, just with extra steps and pauses.The following version is more verbose -- which makes it feel slower -- but can provide dramatic speed ups even for a single user by overlapping requests so that they run concurrently:
var fooTask = GetFooAsync(...);
var barTask = GetBarAsync(...);
var bazTask = GetBazAsync(...);
var foo = await fooTask;
var bar = await barTask;
var baz = await bazTask;
Unfortunately, I've literally never seen this design pattern in the field...