Asynchronous Code

IO Bound Non-blocking code

The Asynchronous Programming Patterns (.NET) allows for non-blocking code.
Essentially by setting up a state machine and continuing to run from the calling thread.
Starting with a simple example:
class Program {
    static void Main(string[] args) {
        Run();

        // do something else here (that takes about 2 secs)
        for(int i=0; i<20; i++) {
            Console.Write(".");
            Thread.Sleep(100);
        }
        Console.WriteLine("\r\nPress any key to exit...");
        Console.ReadKey();
    }
    static async void Run() {
        Console.WriteLine("Blocked by synchronous call");
        Console.WriteLine("The result from the synchronous call is {0}", GetCharacterCount());

        Console.WriteLine("Not blocked");
        Console.WriteLine("The result from the asynchronous call is {0}", await GetCharacterCountAsync());
    }
    static int GetCharacterCount() {
        var client = new HttpClient();
        var page = client.GetStringAsync("https://www.dotnetfoundation.org").Result;

        return page.Length;
    }
    static async Task GetCharacterCountAsync() {
        var client = new HttpClient();
        var page = await client.GetStringAsync("https://www.dotnetfoundation.org");

        return page.Length;
    }
}
The output looks like:
Blocked by synchronous call
The result from the synchronous call is 30873
Not blocked
.................The result from the asynchronous call is 30873
...
Press any key to exit...
What has happened here?
The first call, GetCharacterCount, returns the character count of the text from the website.
GetCharacterCountAsync does the same.
The former blocked the calling thread until the text was returned.
The latter has not blocking the calling thread, and waits for a callback.
Therefore, the non-blocking method GetCharacterCountAsync, allowed the calling thread to continue processing.

CPU Asynchronous Code

Another form of asynchronous programming, according to Microsoft's definition , is CPU bound work.
Defined as different to the IO Bound work, in that, a task is assigned to the CPU and callsback after processing ends.
A task is spawned, using Task.Run()and the OS queues the task.
The task runs concurrently and any result returned to the main calling thread.
An example of this is:
class Program {
    static void Main(string[] args) {
        Run();

        // do something else here (that takes about 2 secs)
        for(int i=0; i<20; i++) {
            Console.Write(".");
            Thread.Sleep(100);
        }
        Console.WriteLine("\r\nPress any key to exit...");
        Console.ReadKey();
    }
    static async void Run() {
        Console.WriteLine("The expensive calculation result is {0}", await CalculateResult());
    }
    static async Task CalculateResult() {
        int x = 0;
        // This queues up the work on the threadpool.
        var expensiveResultTask = Task.Run(() => {
            for (int i = 0; i < 10; i++) {
                x += i;
                Thread.Sleep(100);
            }
            return x;
        });
        // Execution of CalculateResult is yielded here!
        return await expensiveResultTask;
    }
}
The output looks like:
..........The expensive calculation result is 45
..........
Press any key to exit...
Note the Task.Run, in the CalculateResult method.
Then, yielding using the await, which starts the extra resources.
It's important to remember that another CPU resource is used, which could be more expensive
Mentioned in Microsoft's website is this type of concurrency should not used for tight loops.

Summary

The .NET Async patterns are very simple to use, just add the async keyword to a method and either call a resource with the await keyword or use the Task.Run method (and then await).
One just has to remember

  • if looking for a resource from another server to use the Non-blocking pattern.
  • if doing CPU intensive work to use the CPU Asynchronous pattern.
Microsoft state to be careful when using LINQ. It utilises lazy loading and needs the .ToList() or .ToArray() to force the generation of the sequences.

References

Asynchronous Programming Patterns
Microsoft async
Asynchronous programming
Async in depth
Futures and promises
C# In Depth website
C# In Depth
Writing High Performance .NET Code