The new asynchronous capabilities of .NET 4.5 rely on the async
and await
modifiers. Basically we have two important points here:
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.Here we will use the
async
and await
features in a basic way to clearly understand them.
caAsyncAwait
.System.Net.Http
assembly.Program.cs
file, add the following using
clauses:using System.Net; using System.IO;
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(); }
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(); }
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.."); }
HttpTestAsync
in the Main
method and next to it add a call to MultipleHttpTestAsync
.Main
method ends. If we execute it several times, their finishing order might change.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.."); }
Main
method to this new method.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.
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.