To wrap up our discussion of the async/await pattern, I wanted to mention a common error:
This async method lacks 'await' operators and will run syncrhonously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
Here's how we could change the code from our sample to produce the error. I have changed line 33 from...
var task = strm.WriteAsync(bytes, 0, bytes.Length);
await task;
...to the non-Async version:
strm.Write(bytes, 0, bytes.Length);
class Program
{
static void Main(string[] args)
{
WriteALot();
Console.ReadLine();
}
static async void WriteALot()
{
Task task;
using (new CodeTimer("Calling WriteFileAsync"))
task = WriteFileAsync();
using (new CodeTimer("Awaiting WriteFileAsync"))
await task;
}
static async Task WriteFileAsync()
{
using (new CodeTimer("Executing WriteFileAsync"))
{
int writesDone = 0;
int writesDesired = 5;
var bytes = new byte[102400];
var tempFile = Path.GetTempFileName();
using (var strm = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true))
{
for (writesDone = 0; writesDone < writesDesired; ++writesDone)
{
using (new CodeTimer("WriteAsync with its await"))
{
strm.Seek(0, SeekOrigin.Begin);
strm.Write(bytes, 0, bytes.Length);
}
}
}
}
}
}
The result is synchronous execution:

You'd think that the Write call would be the perfect moment for the program to take advantage of multi-threading and go back and do some work in the calling routine, right? Yes, that's right ... until we realize once again that async/await is single-threaded. The only time it does something that looks sort of like multi-threading is when you call one of the special Async methods in the .NET API or when you await a Task.
The first post in this series has an example of calling an Async API method:
var task = strm.WriteAsync(bytes, 0, bytes.Length);
await task;
Equivalently, you could do this:
await strm.WriteAsync(bytes, 0, bytes.Length);
The Task.Run strategy would look like this. (Normally, you'd only use this for CPU-bound operations. It's better to use an Async API method if one is available.)
await Task.Run(() => strm.Write(bytes, 0, bytes.Length));
Any of the above will produce output similar to this, showing that execution passed back to the caller upon the await, as explained in the previous post.
