Understanding async and await in .NET 4.5

The new asynchronous capabilities of .NET 4.5 rely on the async and await modifiers. Basically we have two important points here:

  • The async modifier indicates to the compiler that a method or lambda expression is asynchronous—we call them async methods.
  • The await operator, which can only be used within an async method, is applied to a task to suspend execution of the method until the task is complete. Meanwhile, the control is returned to the caller of that method.

How to do it...

Here we will use the async and await features in a basic way to clearly understand them.

  1. Create a new Visual Studio project of type Console Application named caAsyncAwait.
  2. Add a reference to the System.Net.Http assembly.
  3. In the Program.cs file, add the following using clauses:
    using System.Net;
    using System.IO;
  4. Next, add the following methods:
    Static async Task HttpTestAsync(String url) {
    byte[] result = await GetURLContentsAsync(url);
    Console.WriteLine("Received {0,8} bytes..", result.Length);
    }
    private static async Task<byte[]> GetURLContentsAsync(string url)
    {
    var content = new MemoryStream();
    var webReq = (HttpWebRequest)WebRequest.Create(url);
    using (WebResponse response = await webReq.GetResponseAsync())
        {
        using (Stream responseStream = response.GetResponseStream())
            {
            Await responseStream.CopyToAsync(content);
            }
        }
    Return content.ToArray();
    }
  5. Add a call to the HttpTestAsync function in the Main method surrounded with some sentences in the Console.Writeline method to keep track of what is happening:
    static void Main(string[] args)
    {
    Console.WriteLine("Start of Main Method");
    HttpTestAsync("http://www.packtpub.com/forthcoming-titles");
    Console.WriteLine("End of Main Metod");
    
    Console.ReadLine();
    }
  6. We should execute the application and get the results shown in the following screenshot:
    How to do it...
  7. Next, add the following method:
    Static async void MultipleHttpTestAsync()
    {
        Task t1 = HttpTestAsync("http://www.packtpub.com/forthcoming-titles");
        Task t2 = HttpTestAsync("http://www.silverlightguy.com");
        Task t3 = HttpTestAsync("http://www.microsoft.com");
    await t1;
    await t2;
    await t3;
    
    Console.WriteLine("All tasks have finished..");
    }
  8. Comment the previous call to HttpTestAsync in the Main method and next to it add a call to MultipleHttpTestAsync.
  9. If we execute the code, we will see that the different tasks are executed after the Main method ends. If we execute it several times, their finishing order might change.
    How to do it...
  10. Now, we will add a similar method:
    Static async void OptimizedMultipleHttpTestAsync()
    {
        Task t3 = HttpTestAsync("http://www.packtpub.com/forthcoming-titles");
        Task t2 = HttpTestAsync("http://www.silverlightguy.com");
        Task t1 = HttpTestAsync("http://www.microsoft.com");
    
        Task[] tasklist= new Task[] { t1, t2, t3 };
        Await Task.WhenAll(tasklist);
    
    Console.WriteLine("All tasks have finished..");
    }
  11. Then we will change the call from the Main method to this new method.
  12. If we execute it, we get practically the same output as with the previous code.

How it works...

We have initially created the HttpTestAsync method, adding to it the async modifier, which indicates that the method (or the lambda expression) is asynchronous. These methods are called asyc methods.

An async method provides the ability to be called without blocking the caller's thread, which is convenient for long-running jobs. Also, the caller of an async method resumes its work without waiting for the async method to finish, unless we indicate in the call to the async method that we wish to wait until it finishes; we will do that with the await expression.

The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task is completed. Basically, it waits for the completion of the task. Nowadays, the thread is not blocked and the process continues, but the rest of the code after the await operator becomes an automatic callback method.

It is obvious that the task where the await operator is applied must be modified by the async modifier and returns a task or task of TResult, that is, when the task is returned by an async method, it might not be the source of the task.

Additionally, by convention, all asynchronous method names should end in Async.

Going back to the HttpTestAsync method we just commented, we have marked it as async and it is returning a task that we can wait for with the await operator. Inside it, because it is an async method, it can await the completion of the GetURLContentsAsync method.

The GetURLContentsAsync method is an async method that retrieves a URL with a WebRequest method, gets its content as a response, and returns it when it is finished.

HttpTestAsync takes the resultant content from GetURLContentsAsync as we are waiting for it to finish with await and writes on the console the total amount of bytes received.

We execute the first test with the following lines of code:

Console.WriteLine("Start of Main Method");
HttpTestAsync("http://www.packtpub.com/forthcoming-titles");
Console.WriteLine("End of Main Metod");

We continue with the Main method before the awaited GetURLContentsAsync method finishes so that the main console writelines are written first.

In the next example we code, MultipleHttpTestAsync, we are creating three tasks to download three URLs asynchronously and then we await them. The tasks are being executed in parallel since they are started at creation. The await expression only indicates that the processing can't continue until the task finishes.

So with this code, we really are controlling the start time of the tasks (that is, the async methods are called) but not their end time. The order of the await operators can affect the times a bit but they might finish before arriving at the await expressions:

Task t3 = HttpTestAsync("http://www.packtpub.com/forthcoming-titles");
Task t2 = HttpTestAsync("http://www.silverlightguy.com");
Task t1 = HttpTestAsync("http://www.microsoft.com");

await t1;
await t2;
await t3;

A more elegant solution is what we will do in the next example, where we add all the tasks to an array and use the Task.WhenAll method on this generated collection of tasks:

Task[] tasklist = new Task[] { t1, t2, t3 };
await Task.WhenAll(tasklist);

This method asynchronously awaits multiple asynchronous operations that it expects as an IEnumerable of tasks.

This way the code will resume when all the tasks have been completed, not before or after.

There's more...

We have seen the basics of async and await, explored task handling, and even executed some the tasks in parallel. We ended up using a method from the Task class, WhenAll, which enabled us to wait for a list of tasks to finish.

But there is a lot more to explore with task management, which you will be familiar with if you have already explored the TPL. We have plenty of options there to control the processing flow of our application in ways that would have been extremely complicated earlier.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset