Sunday, 28 October 2012

Asynchronizing a C# method using async and await

In the business applications that we build as part of our job consist of several heavy weight operations like file manipulations, dynamically creating images, generating an excel file from a result set and the list goes on.

In such scenarios, we cannot let our application to halt till the requested operation is completed, as the operation takes a lot of time. What we can do is, assign the heavier operation to a separate task and do something that is independent of result of the operation till the operation is completed.

I have a simple console application that consists of methods performing add and divide arithmetic operations. Sleep method is called in the Divide method to make the execution slow. Code of the console application is shown below:
static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
            
    int first = 5;
    int second = 10;

    Console.WriteLine(Add(first, second));
    Console.WriteLine(Divide(second, first));
    Console.WriteLine(Divide(second, first));

    watch.Stop();
    Console.WriteLine("Time taken: {0}",watch.ElapsedMilliseconds);
}

static int Add(int first, int second)
{
    return first + second;
}

static double Divide(int second, int first)
{
    System.Threading.Thread.Sleep(2000);
    return (double)second / first;
}

If you run the application, the value of watch.EllapsedMilliseconds would be around four seconds. This is because, we are calling the Divide method twice synchronously. The thread executing the application waits until the first method call is completed and the result is returned before proceeding to the second call.

We can reduce the time taken by this application using Task Parallel Library (TPL). We can create a Task for each of the slower operation and continue with other operations without waiting for the Tasks to finish. Following snippet shows how to create a Task and get the result once the task is finished.

var taskName = Task.Factory.StartNew<returntype>(() => MethodToCall(arguments));
//Perform other independent operations here
...
...
...
returntype variable = taskName.Result;

Let’s use this feature in the demo application. Create two tasks, one for each division call and use the result to print it on the screen. Replace the statements displaying results on the console with the following statements:
var divisionTask = Task.Factory.StartNew<double>(() => Divide(second, first));
var secondDivisionTask = Task.Factory.StartNew<double>(() => Divide(second, first));
Console.WriteLine(divisionTask.Result);
Console.WriteLine(secondDivisionTask.Result);
Run the application. Time taken now is around two seconds. So, the difference in time taken is significant. We may say that both the division tasks finish almost at the same time.

Though this approach reduced the time taken, it demands the programmer to create tasks manually and manage them. It might become quite difficult for us to manage an application that involves creating a large number of tasks. To avoid this problem, the C# language designers have added the async and await keywords. These keywords can be used in an application built using Visual Studio 2012 and targeted to .NET Framework 4.5.

A method performing a heavier or slower operation should be marked as async and the statement in that method that takes a lot of time to finish should be marked as await. The await keyword indicates that a slow operation is going to start. Once the currently running thread finds a statement marked with await, it goes to perform some other operation without waiting for the statement to complete. The await can be applied with a Task. For example, if a method call has to be marked as await, the method should return a Task.

Return type of an async method can be either void or Task. The C# compiler generates a bunch of code when an async method is compiled. It in turn uses the Task Parallel Library.

Following is the modified Main method and the Divide method using the async and await keywords:
static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    int first = 5;
    int second = 10;
            
    Console.WriteLine(Add(first, second));
    var divisionTaskAsync = DivideAsync(second, first);
    var secondDivisionTaskAsync = DivideAsync(second, first);
    Console.WriteLine(divisionTaskAsync.Result);
    Console.WriteLine(secondDivisionTaskAsync.Result);
            
    watch.Stop();
    Console.WriteLine("Time taken: {0}", watch.ElapsedMilliseconds);
}

static async Task<double> DivideAsync(int second, int first)
{
    await Task.Delay(2000);
    return (double)second / first;
}

Call to Thread.Sleep is replaced with Task.Delay as the later returns a Task. I renamed the Divide method to DivideAsync just to follow the convention that is already used by the framework methods. Otherwise, it doesn’t make any difference.

Happy coding!

3 comments:

  1. Ravi, what is "async" in the DivideAsync method?

    ReplyDelete
  2. Vishnu,

    async keyword denotes that the method DivideAsync executes asynchronously. An async method must use the await keyword somewhere in the body of the method. Also, notice the return type and the return value of the method. The async keyword automatically wraps the returned value inside a Task, we don't need to create a Task manually to return from the method.

    You may check the MSDN documentation to learn more: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

    ReplyDelete