C# Corner
Asynchronous Programming with the Async CTP
The Async CTP and async and await keywords allow C# (and VB) developers to easily create more responsive applications. Here's how to get started with the Async CTP.
The Async Community Technology Preview (CTP) is a freely available download for Visual Studio 2010. The Async CTP includes the async and await keywords that are being considered for the next iterations of C# and VB.NET. Both language features allow you to more easily leverage the asynchronous programming features of the .NET Framework. The async keyword allows you to designate a method as being an asynchronous method. The await keyword allows you to indicate an expression to evaluate upon completion of an asynchronously invoked method.
Let’s go through the process of getting the Async CTP set up, followed by a look at some practical applications.
Getting Started
First download the Async CTP. Before installing the CTP ensure that you do not have the ASP.NET MVC 3 Beta or RC installed, as this will cause issues with the Async CTP. Trust me on this one. Also be sure that you do not have any Visual Studio 2010 hotfixes installed that have modified the C# or VB.NET runtimes -- as discussed here. Furthermore do not install the Visual Studio 2010 Service Pack 1 if you want to try out the Async CTP, as they are not currently compatible.
Now that you know what not to do, go ahead and install the Async CTP and verify that the examples are working correctly. If the examples do not compile correctly, double check that you do not have any of the aforementioned incompatible Visual Studio 2010 updates/hot fixes installed. I recommend installing the CTP on a development virtual machine. We will get started with creating an asynchronous method.
First, we'll set up our first project for the Aysnc CTP. Create a new .NET 4 C# Console Application and add a reference to AsynchCtpLibrary.dll. The AsynchCtpLibrary.dll file will be located in your Windows user Documents directory under “Microsoft Visual Studio Async CTP\Samples”.
Creating an asynchronous method
Creating an asynchronous method involves creating a method with the async keyword and returning either void, Task, or Task<T>. Let’s start out simple and create an asynchronous method with a void return type that simply greets the user given their name.
static async void GreetUserAsync(string name)
{
await TaskEx.Run(() => Console.WriteLine("Hello, {0}", name));
}
GreetUserAsync is declared as an async method and awaits one task, which outputs “Hello, name” to the console where name is the given name to the function. TaskEx.Run creates a Task that executes the Console.WriteLine function. You may be asking why couldn’t I simply call Console.WriteLine("Hello, {0}", name)) within GreetUserAsync? The answer is you can, but then the GreetUserAsync method would execute synchronously. The await expression will call the created task, allow the main thread to run, and will force the GreetUserAsync function to return once its task has completed.
Calling the asynchronous method:
static void Main(string[] args)
{
Console.WriteLine("Async CTP Simple Console App");
Console.Write("Name:");
string name = Console.ReadLine();
Console.WriteLine("Calling asynch method...");
GreetUserAsync(name);
Console.ReadLine();
}
A more complex example
Now that we have covered the basics, let’s create a more complex application that takes a given number and performs several calculations on the method in parallel and displays the results in real-time. The application will compute the absolute value, square root and cube of a given number and compute a total once the other calculations have finished.
The first step is to open up Visual Studio 2010 and create a new WPF C# Application. Next add a reference to AsynchCtpLibrary.dll just as we did in the previous example. Now open up the MainWindow.xaml.cs and insert the following markup between into the element component.
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Number</Label>
<TextBox Name="txtNumber" MinWidth="100"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Absolute Value</Label>
<Label Name="lblAbsVal"></Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Square root</Label>
<Label Name="lblSqrtVal"></Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Cube</Label>
<Label Name="lblCubeVal"></Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Total</Label>
<Label Name="lblTotalVal"></Label>
</StackPanel>
<Button Name="btnCompute" Click="btnCompute_Click">Compute</Button>
</StackPanel>
[Click on image for larger view.] |
Figure 1. |
Run the application and you ensure that your application looks like the above screen shot. Now that our GUI is created we can start adding the core logic to our application. We’ll start out with adding the asynchronous method to calculate the absolute value of a given number.
async Task<double> ComputeAbsAsync(double number)
{
await TaskEx.Delay(1000);
return await TaskEx.Run<double>(new Func<double>(() => System.Math.Abs(number)));
}
The ComputeAbsAsync method contains two await expressions. The first await expression tells the method to wait for one second asynchronously. The second await expression creates and runs a task that computes the absolute value of the given number. Next we will add the ComputeSqrtAsync method which will compute the square root of a given number asynchronously.
async Task<double> ComputeSqrtAsync(double number)
{
await TaskEx.Delay(1000);
return await TaskEx.Run<double>(new Func<double>(() => System.Math.Sqrt(number)));
}
As you can see the method is almost identical to the ComputeAbsAsync method. Feel free to remove the TaskEx.Delay in your application. I added the delay to more easily display that the main thread is still active during the asynchronous method calls. You may be wondering if there is any easy way to refactor the code to allow you to execute a given Task asynchronously. The answer is a resounding yes. It turns out that the await expression can execute any Task or Task<T> in an asynchronous manner. We’ll execute the cube function in this manner within our ComputerResultsAsync method.
async Task<double> ComputeResultsAsync(double number)
{
Task<double> cubeTask = TaskEx.Run<double>((() => System.Math.Pow(number, 3)));
double absVal = await ComputeAbsAsync(number);
lblAbsVal.Content = absVal;
double sqrtVal = await ComputeSqrtAsync(number);
lblSqrtVal.Content = sqrtVal;
double cubeVal = await cubeTask;
lblCubeVal.Content = cubeVal;
return absVal + sqrtVal + cubeVal;
}
The ComputeResultsAsync method first creates a Task<double> that will calculate the cube of the given number. Next we await the ComputeAbsAsync, ComputeSqrtAsync methods as well as the cubeTask. Between each await we update the displayed value on the form to the result of pertinent calculation. Lastly, we return the total of all of the calculations. You may have noticed that each of our async methods returns a Task<double> in their respective definitions, but actually returns a double when invoked through an await expression. If your async method does not need to return a result you can simply return void or Task, as we did in the first example.
Now that our core application logic has been implemented it is time to wire up the Compute button click event and update our form.
private async void btnCompute_Click(object sender, RoutedEventArgs e)
{
double number = double.Parse(txtNumber.Text);
double total = await ComputeResultsAsync(number);
lblTotalVal.Content = total;
}
In our button click event, we retrieve the number the user entered into the textbox, call the ComputeResultsAsync method asynchronously and update the displayed total. The button click event itself has been declared as an asynchronous event. By making the click event execute asynchronously we are able to easily invoke the ComputeResultsAsync method asynchronously and update the displayed result once the total has been calculated.
Finishing Touches
The application is completed as is, but can use some further refinement. The application is completed and will function correctly if the Compute button is clicked in succession, but it will end up creating many Task objects. Also the results are not cleared before a new computation is executed. To fix the first issue we can simply disable the compute button at the beginning of the click event and re-enable it once the total has been displayed. To fix the second issue we will clear any labels that display the calculated results before the new results are calculated. The updated button click event code is:
private void ClearResults()
{
lblAbsVal.Content = string.Empty;
lblCubeVal.Content = string.Empty;
lblSqrtVal.Content = string.Empty;
lblTotalVal.Content = string.Empty;
}
private async void btnCompute_Click(object sender, RoutedEventArgs e)
{
btnCompute.IsEnabled = false;
ClearResults();
double number = double.Parse(txtNumber.Text);
double total = await ComputeResultsAsync(number);
lblTotalVal.Content = total;
btnCompute.IsEnabled = true;
}
Our application is now completed and fully functional!
[Click on image for larger view.] |
Figure 2. |
Conclusion
The new language features async and await integrate very smoothly with the existing Task Parallel Library in .NET 4 and definitely make it easier to both create and call asynchronous methods. I highly recommend checking out the Asynch CTP if you are interested in asynchronous programming and/or new C# language features coming down the pipe.
About the Author
Eric Vogel is a Senior Software Developer for Red Cedar Solutions Group in Okemos, Michigan. He is the president of the Greater Lansing User Group for .NET. Eric enjoys learning about software architecture and craftsmanship, and is always looking for ways to create more robust and testable applications. Contact him at [email protected].