The philosophy behind "all async" is to facilitate non-blocking I/O.
That is, your primarily async code can potentially let the environment prioritize how your application or service is being executed and achieve as much parallelized execution as possible in a multi-threaded, multi-process system.
For example, ASP.NET Web API, ASP.NET MVC or even ASP.NET Web Forms (code-behind) can take advantage of all async to continue attending Web requests to other users while some async operation is being executed. Thus, even when a Web server like IIS or Katana might limit the number of concurrent requests, async operations are executed in a separate thread from the request thread, and this is allows the Web server to respond to other requests while async operations get a result and they need to continue:
// While WhateverAsync is being executed, current thread can be used
// by a new request and so on.
// Obviously, this will work this way if WhateverAsync actually
// does its work in another thread...
await WhateverAsync();
So... do you need to implement everything asynchronously? Even when you return a Task
you don't need to provide an asynchronous implementation:
public Task WhateverAsync()
{
// This creates a fake Task object which
// simulates a Task that has already ended successfully
// and without creating a child thread!
// This, this method is a SYNCHRONOUS implementation unless
// the whole method doesn't execute asynchronous operations.
return Task.FromResult(true);
}
My point of view here is...
...implement everything returning a Task and using the Async
suffix at the end of method's identifiers (WhateverAsync
, WhoKnowsAsync
, DoStuffAsync
...)...
...unless you can be sure that the whole method will always execute a very simple things which can't block application/service's thread for a long time (long time can be few miliseconds, now imagine a code which doesn't block main app thread for 100ms whenever some method is called and your code can prioritize executing something while it awaits 100ms....). I would include here string manipulation, simple arithmetic operations, configuration methods...
If your code isn't async today, you can turn it into actual async operations without affecting the entire code base, as you only need to change Task.FromResult<T>(T result)
calls to actually return an unfinished Task
instance.
At the end of the day, your methods have an async signature and dependencies on them don't care if they're actually asynchronous, and these method implementations decide what's asynchronous or synchronous instead of giving this responsibility to the caller..