With the .NET Framework 4.5 the new keywords “async” and “await” were introduced. These keywords will aloe an asynchronous programming which is nearly as easy as synchronous programming. With this article I want to give you a crash course into this topic.
Let’s start with a little example. The following source code shows a WPF application with a button click event. Within this event an asynchronous method call is executed.
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Click(object sender, RoutedEventArgs e) { DoSomething(1); await DoSomethingAsync(2); DoSomething(3); } private void DoSomething(int x) { } private async Task DoSomethingAsync(int x) { var task = Task.Run(() => {}); await task; } }
What will happen within the button click method? At first the method “DoSomething(1)” is executed. As the execution is synchronous, the UI is blocked during this time. Next the method “DoSomethingAsync(2)” is executed. With the “await” keyword we will now return the control to the caller, in this case the UI thread. The method “DoSomethingAsync(2)” will be executed asynchronous. As this method is finished, the remaining part of the calling method is executed and so “DoSomething(3)” is executed.
This little example shows the nice implementation concept of async+await. You can implement your method in the normal synchronous style but by adding the new keywords the execution flow changes to asynchronous.
To create an asynchronous function you have to add the “async” keyword an change the return value to a task. In case you method returns void the Task is without a parameter, otherwise it is a Task where T is type of your return value. The caller can use the returned Tasks variable to check its status. Sometimes you may also have a void as return value. But this is used for fire and forget events only, like in the above example the button clock event.
The async and await keyword will not start an own task. Therefore your method is executed asynchronous only if the called method creates a task and awaits it end. You will see this within the example in method “DoSomethingAsync(2)”. A task is created and started and with the await keyword we wait for the end of the task.
As mentioned above, the big advantage of this implementation pattern is the high similarity of synchronous and asynchronous code. This increases the readability of the otherwise difficult asynchronous method calls. Furthermore it will allow you to change your existing applications from an synchronous to an asynchronous behavior without the need of a refactoring. Of course, the async await pattern will offer some other nice features, like an easy aggregated error handling, but this should not be shown within the context of this crash course. Instead, I want to finish this article with an example how to change existing synchronous code to asynchronous one.
The following source code shows an example of a simple user interface with a button and a text box. On button click a long running calculation is done and the result is shown within a text box.
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Calculate_Click(object sender, RoutedEventArgs e) { Calculator calculator = new Calculator(); int result; result = calculator.Calculate(5, 7); TextBox_Result.Text = result.ToString(); } } public class Calculator { public int Calculate(int a, int b) { Thread.Sleep(TimeSpan.FromSeconds(3)); return a + b; } }
During the execution of the calculation the user interface is blocked. Therefore we want to change the implementation to the asynchronous pattern. This can be done with some minor modifications. The long running part is executed within a task. The async and await kewords are added to the calculation method and the return value is changed to Task. Furthermore the async and await keywords are added to the event method too. The following source code shows the modified application.
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Calculate_Click(object sender, RoutedEventArgs e) { Calculator calculator = new Calculator(); int result; result = await calculator.CalculateAsync(5, 7); TextBox_Result.Text = result.ToString(); } } public class Calculator { public async Task<int> CalculateAsync(int a, int b) { var task = Task.Run(() => { Thread.Sleep(TimeSpan.FromSeconds(3)); return a + b; }); return await task; } }
Now the calculation is executed asynchronous and the user interface stays responsible. All the task management magic is done by the compiler. The source code modifications were marginal and the resulting source code is nearly identical to the origin source code.
Furthermore this example shows another nice feature of the async await pattern. Normally if you execute code in an own task, this task cannot update user interface elements directly. But in this scenario it is working. This nice behavior is possible because the code behind the await statement is executed in the origin context. This default behavior is mainly needed in user interface code and can be disabled in all other cases with the task method “ConfigureAwait(false)”.