12 out of 22 rated this helpful - Rate this topic

Asynchronous Programming with Async and Await (C# and Visual Basic)

Visual Studio 11

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

Visual Studio 11 Developer Preview introduces a simplified approach to asynchronous and concurrent programming that makes code easier to write, understand, and maintain.

The approach relies on two new keywords, the Async (Visual Basic) or async (C#) modifier and the Await (Visual Basic) or await (C#) operator. The Async or async modifier indicates to the compiler that a method or lambda expression is asynchronous. A method that is marked with the Async or async modifier is referred to as an async method.

Inside an async method, the Await or await operator is applied to a task to suspend execution of the method until the task is complete. In the meantime, control is returned to the caller of the method. The suspension is accomplished without exiting the async method, and it does not cause finally blocks to run.

The compiler does the difficult work that used to fall to the developer, 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 is similar to synchronous code. In addition, routine processes that can be difficult in traditional asynchronous code, such as loops and exception handling, cease to be roadblocks to successful solutions.

The following example illustrates the simplicity of this approach by comparing a method that is written synchronously with the same method written asynchronously. For the full step-by-step example, see Walkthrough: Writing an Async Program (C# and Visual Basic).

Only the following changes are required to convert a synchronous method (GetURLContents) to an asynchronous method (GetURLContentsAsync).

  • In the method signature, make the following changes:

    • Mark the method with the Async or async modifier.

    • Change the return value from Byte() to Task(Of Byte()) (Visual Basic) or from byte[] to Task<byte[]> (C#).

    • 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 to GetResponse 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.

That's it. Those few steps complete the conversion.


// Synchronous version of a method that downloads the resource that a URL
// links to and returns its content.
private byte[] GetURLContents(string url)
{
    // The download ends up in variable 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 lines that are 
// changed are marked with **.

// **Change the method name and the return type. Add the async modifier.
private async Task<byte[]> GetURLContentsAsync(string url)
{
    // The download ends up in variable 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();
}

Async and Await Keywords

A method that is modified by the Async or async modifier is referred to as an async method. An async method typically contains one or more occurrences of the Await or await operator, but the absence of an operator does not cause a compiler error. The compiler issues a warning for such methods, because async methods that do not contain an Await or await operator are not expected and might indicate an error. If an async method doesn’t use the Await or await operator, the method isn’t suspended and executes as a synchronous method does, despite the Async or async modifier.

The Async or async modifier is a contextual keyword. In Visual Basic, it can be applied to a method or a lambda expression. In C#, the modifier can be applied to a method, a lambda expression, or an anonymous method. In all other contexts, the term is interpreted as an identifier.

Await or await is also a contextual keyword. It is interpreted as a keyword only in the following limited circumstances. Elsewhere, it is considered to be an identifier.

  • In Visual Basic, Await is a keyword only in the body of an immediately enclosing method or lambda expression that is modified by Async. Within the method or lambda expression, an Await expression cannot occur in a query expression, in the catch or finally block of a Try…Catch…Finally statement, or in the body of a SyncLock statement.

  • In C#, await is a keyword in the body of an immediately enclosing method, lambda expression, or anonymous method. In this context, an await expression cannot be used in a synchronous function, in a query expression, in the catch or finally block of an exception handling statement, in the block of a lock statement, or in an unsafe context.

Async Method Return Types

In Visual Basic, an async method is either a Sub procedure, or a Function procedure that has a return type of Task or Task<TResult>.

In C#, an async method can have a return type of void, Task, or Task<TResult>.

The method cannot declare any ByRef parameters in Visual Basic, or any ref or out parameters in C#, although it can call methods that have such parameters.

A 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 is a Sub procedure or that returns void cannot be awaited. To enable the callers of an async method to await its completion, use a return type of Task or Task(T).

In most async methods, you specify Task(T) for the return type if the Return (Visual Basic) or return (C#) statement of the method specifies an operand of type T. You use Task if the method has no Return or return statement. You can think of the Task return type as meaning "Task(void)." That is, a call to the method returns a Task, but when the Task is completed, no meaningful value is produced.

Naming Convention

By convention, the suffix "Async" is added to the names of methods that are modified by the Async or async modifier.

Async methods that return void are discouraged except when they are used to start off a separate asynchronous flow of processes where callers of the method have no need to coordinate with the results.

Exceptions to the convention can be made where an event, base class, or interface contract suggests a different name. For example, the names of common event handlers, such as button1_Click, are best not renamed.

Threads

Async methods are intended to be non-blocking operations. An await expression in an async method does not 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, using time on the thread only when it's active.

Did you find this helpful?
(1500 characters remaining)