Assuming the starting point would have no process/thread/task control and be a non-responsive spinning loop, checking if the time has passed e.g.:
public void SleepBadly(int millisecondsTimeout)
{
var stopTime = DateTime.UtcNow.AddMilliseconds(millisecondsTimeout);
while (DateTime.UtcNow < stopTime) {}
return;
}
SleepAsyncA sleeps the thread rather than spinning so it doesn't use any CPU, so would be responsive as the CPU is available, but it is still using the thread while it sleeps.
SleepAsyncB gives up the thread while it waits, so it doesn't use CPU and that thread can be used for something else; so it is responsive and scalable.
For example, at scale, if you had 100,000 calls outstanding in SleepAsyncA; either you would have exhausted the threadpool and they would start queuing or you would have 100,000 active threads, neither of which is very good for scalability.
SleepAsyncB on the other hand would be using 0 threads while the 100,000 calls were waiting and doing nothing is infinitely more scalable than doing something.
However, while SleepAsyncB is a good example of how to use Task constructs like TaskCompletionSource, what you'd probably want to actually do in this example is:
public Task SleepAsyncC(int millisecondsTimeout)
{
return Task.Delay(millisecondsTimeout);
}