Friday, August 17, 2012

Asynchronous Programming with Async and Await


When you use asynchronous programming, you specify points in your code where potentially long running processes are suspended while other parts of the program can continue. This technique avoids possible performance bottlenecks and enhances the overall responsiveness of your application. Asynchrony is important for activities that are potentially blocking, such as when your program accesses the web. If such an activity is blocked within a synchronous process, the entire program is blocked. In an asynchronous process, the program can make progress in other areas while the blocking task finishes its work.
Asynchrony is especially valuable for processes that access the UI thread because all UI-related activity usually shares one thread. If any process is blocked, all are blocked.
For an example of a blocked process, follow the steps in Walkthrough: Accessing the Web by Using Async and Await (C# and Visual Basic) through the "To test the synchronous solution" section. As an alternative, you can download the code for the walkthrough from Async Sample: Accessing the Web Walkthrough and run the project that’s named SyncWalkthrough. When the UI thread is synchronously downloading content from the web, you can't move or resize the window. You can’t even close it to end the program if you don't want to wait.
The Async (Visual Basic) or async (C#) modifier and the Await (Visual Basic) or await (C#) operator are fundamental to async programming. The async modifier indicates to the compiler that a method or lambda expression is asynchronous and that you can use await operators to designate suspension points within the method. This kind of method is referred to as an async method.
Inside an async method, you can apply an await operator to a particular task to suspend execution of the async method until the awaited task is complete. In the meantime, control is returned to the caller of the async method. The suspension doesn't constitute an exit from the async method, and finally blocks don’t run.
The compiler does the difficult work that the developer used to do, including signing up continuations for the completion of the suspended method. As a result, asynchronous code is much easier to write, and your program retains a logical structure that resembles synchronous code. For example, some routine processes, such as loops and exception handling, can be difficult to write in traditional asynchronous code. In an async method, you write these elements much as you would in a synchronous solution, and the problem is solved. For more information about previous approaches to asynchrony in the .NET Framework, seeTPL and Traditional .NET Asynchronous Programming.
The .NET Framework 4.5 contains many members that work with async and await. You can recognize these members by the "Async" suffix that’s attached to the member name and a return type of Task or Task. For example, the System.IO.Stream class contains methods such as CopyToAsyncReadAsync, and WriteAsyncalongside the synchronous methods CopyToRead, and Write.
The following example illustrates the simplicity of this approach by comparing a method that's written synchronously with the same method if it were written asynchronously. For the full example, see Walkthrough: Accessing the Web by Using Async and Await (C# and Visual Basic).
The following changes convert a synchronous method (GetURLContents) to an asynchronous method (GetURLContentsAsync).
  • Change the method signature in the following ways.
    • Mark the method with the Async or async modifier.
    • Change the return type from Byte() to Task(Of Byte()) in Visual Basic or from byte[] to Task<byte[]> in C#.
      The task is a promise to provide a byte array when the asynchronous process is complete. For more information about async return types, seeAsync Return Types (C# and Visual Basic).
    • By convention, add the suffix "Async" to the method name.
  • In the body of the method, make the following changes.
    • Replace calls to long-running synchronous methods with calls to corresponding asynchronous methods. In this example, replace the call toGetResponse with a call to GetResponseAsync.
    • Apply the Await or await operator to the result of the method call.
    • Replace the call to CopyTo with a call to CopyToAsync.
    • Apply the Await or await operator to the result of the method call.
The conversion is complete. For the full example and step-by-step instructions, see Walkthrough: Accessing the Web by Using Async and Await (C# and Visual Basic).
// Synchronous version of a method that downloads the resource that a URL
// links to and then returns its content.
private byte[] GetURLContents(string url)
{
    // The downloaded resource ends up in the variable named content.
    var content = new MemoryStream();

    // Initialize an HttpWebRequest for the current URL.
    var webReq = (HttpWebRequest)WebRequest.Create(url);

    // Send the request to the Internet resource, and wait for
    // the response.
    using (var response = webReq.GetResponse())
    {
        // Get the data stream that is associated with the specified URL.
        using (Stream responseStream = response.GetResponseStream())
        {
            // Read the bytes in responseStream, and copy them to content.  
            responseStream.CopyTo(content);
        }
    }

    // Return the result as a byte array.
    return content.ToArray();
}


// Asynchronous version of the same method. The changed lines 

//are marked with **.

// **Add the async modifier. Change the method name and the return type.
private async Task<byte[]> GetURLContentsAsync(string url)
{
    // The downloaded resource ends up in the variable named content.
    var content = new MemoryStream();

    // Initialize an HttpWebRequest for the current URL.
    var webReq = (HttpWebRequest)WebRequest.Create(url);

    // **Call GetResponseAsync instead of GetResponse, and await the result.
    // GetResponseAsync returns a Task<WebResponse>.
    using (WebResponse response = await webReq.GetResponseAsync())
    {
        // Get the data stream that is associated with the specified URL.
        using (Stream responseStream = response.GetResponseStream())
        {
            // ** Call CopyToAsync instead of CopyTo, and await the response.
            // CopyToAsync returns a Task, not a Task<T>.
            await responseStream.CopyToAsync(content);
        }
    }
    // Return the result as a byte array.
    return content.ToArray();
}
An async method is modified by the Async or async modifier. The method typically contains one or more occurrences of the Await or await operator, but the absence of await expressions doesn’t cause a compiler error. If an async method doesn’t use an await operator to mark a suspension point, it executes as a synchronous method does, despite the async modifier. The compiler issues a warning for such methods.
Async , asyncAwait, and await are contextual keywords. For more information and examples, see the following topics:
In Visual Basic, an async method is either a Sub procedure or a Function procedure that has a return type of Task or Task.
In C#, an async method can have a return type of voidTask, or Task.
To enable the callers of an async method to await its completion, use a return type of Task or Task. You specify Task as the return type if the method contains aReturn (Visual Basic) or return (C#) statement that specifies an operand of type TResult. You use Task if the method has no return statement or has a return statement that doesn't return an operand.
Sub method (Visual Basic) or a void return type (C#) is used primarily to define event handlers, where a void return type is required. An async method that’s aSub procedure or that has a void return type can’t be awaited, and the caller of a void-returning method can't catch any exceptions that the method throws.
An async method can't declare ByRef parameters in Visual Basic or ref or out parameters in C#, but the method can call methods that have such parameters.
For more information and examples, see Async Return Types (C# and Visual Basic). For more information about how to catch exceptions in async methods, seetry-catch (C# Reference) or Try...Catch...Finally Statement (Visual Basic).
By convention, you add the suffix "Async" to the names of methods that have an Async or async modifier.
You can ignore the convention where an event, base class, or interface contract suggests a different name. For example, you shouldn’t rename common event handlers, such as button1_Click.
Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.
Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. For information about how to move async methods or lambda expressions to background threads, see TaskRun.

No comments:

Post a Comment