Should we switch to use async I/O by default?

Solution 1:

Using async IO has become very easy with C# 5 but there is still a productivity cost associated with it. For example you need to sprinkle new keywords where previously none where necessary. You have to change the return type of your method.

If you decide later that a method should do IO you have to change the entire call chain to switch to async. It is a non-local change spreading to other modules.

You can't profile async IO. Profiling tools pick up nothing. If you pause the debugger nothing is on any of the thread stacks. Nobody seems to be doing anything. That's because an async IO does not hold a thread. It's just a data structure (an object in the kernel).

The decision also depends on the application type. In a WinForms or WPF app I'd rather go with async because it integrates so nicely into the UI thread.

In an ASP.NET/WCF setting the main advantage is that you don't exhaust the thread pool while you call long-running backend services. If you don't have such a problem, and I think this is rather rare, you gain very little from async IO. In fact you loose performance by default.

In a Metro setting the decision has been made for you. Microsoft (legitimately) chose to trade developer productivity for user experience.

So it is not a clear decision. The pros and cons are both quite weak at this point. For that reason I refrain from giving an unambiguous recommendation. It depends very much on the specific case.

Solution 2:

I would recommend using async when you have a naturally-asynchronous operation, and synchronous code otherwise. It's true that async is slightly slower, but in most cases it's like "turning up the radio in your Hummer" slower.

In UI programs, async increases responsiveness. In server apps, async increases scalability.

AFAIK Windows file I/O internally is async. Looking at this naively it is not clear to me, why async file i/O in .NET should be slower than sync at all.

Asynchronous code is slower because it has to allocate structures to track the asynchronous operation; synchronous code just uses the current thread (and its stack). So the operation itself is not slower, but overall there's a slight speed decrease due to more pressure on the garbage collector.

I generally favor simplicity and robustness and only tune for performance where necessary.

I agree. If you have an operation that is naturally asynchronous (such as I/O), expose an async API. And if you have an operation that is naturally synchronous, expose a synchronous API. Stephen Toub has a couple of great blog posts on this (here and here).