Tuesday, September 3, 2013

Elegant C# Asynchrony

As you know Async is the highly talked and hyped feature of .NET 4.5. With the growing demand for a responsive app all applications need to respond to user interactions and asynchronously process in the background. With this feature Microsoft made the asynchronous programming so simple. In this blog I will show you how to do an asynchronous programming the traditional way and how Microsoft made it so simple. Let’s start of with a small application which calculate the factorial of the given number. In this let’s assume that the calculation (multiplication) take a while and see how we can delegate this to a background process and maintain a responsive user interface by using async and await. I quickly put in a UI screen which calculates the Factorial for the given number and shows the progress while calculating.



Here is the code for calculating the Factorial:
public void Calculate()
{
   int number = Convert.ToInt32(InputTextBox.Text);
   progressBar.Minimum = 1;
   progressBar.Maximum = number;

   long result = 1;
   for (int counter = 1; counter <= number; counter++)
   {
      result = Multiply(result, counter);
      progressBar.Value = counter;
      ResultTextBox.Text = result.ToString();
   }
}

private long Multiply(long x, long y)
{
   Task.Delay(1000).Wait();
   return x * y;
}
As you see in the above code Multiply function takes a while to calculate (I introduced a delay to simulate long processing). Also note that the long running process is inside a loop and needs to be executed sequentially. In other words when I am running the multiply function in background, my UI thread needs to wait for the backend thread to complete. This is needed as I am showing progress for each operation of the backend thread. Instead of going directly to the async and await, I want to show how this can be in the traditional way using Task. As our application needs to execute sequentially by providing a responsive UI we need to substantially rewrite our code. Further we need to ensure that the UI is updated from the main thread and not from background thread. Here is the code using the traditional Task based asynchronous pattern:
public void CalculateTask()
{
   int number = Convert.ToInt32(InputTextBox.Text);
   progressBar.Minimum = 1;
   progressBar.Maximum = number;

   long result = 1;
   Task<long> t = new Task<long>(() => MultiplyTask(result, counter));
   t.Start();
   t.ContinueWith(ContinueTask);
}

private long MultiplyTask(long x, long y)
{
   Task.Delay(1000).Wait();
   return x * y;
}

private void ContinueTask(Task<long> t)
{
   long result = t.Result;
   Dispatcher.BeginInvoke(new Action(delegate
   {
      progressBar.Value = counter;
      ResultTextBox.Text = result.ToString();
   }));

   if (counter <= 10)
   {
      counter++;
      t = new Task<long>(() => MultiplyTask(result, counter));
      t.Start();
      t.ContinueWith(ContinueTask);
   }
}
As you see we need to take care of several things to provide a responsive UI and keeping the same functionality. This coding becomes complex and need a thorough thought. With the asynchrony, Microsoft simplified this design. They made it so natural that the traditional sequential program pattern be used and still do the asynchronous programming. They removed all the complexity of asynchronous programming and gave a simple design. The C# compiler was made smart and was told how to rewrite the code to make synchronous code asynchronous and still maintain the synchronous behavior and thereby providing a better user experience. Here is the initial code tweaked to utilize the async & await features of C#:
public async void CalculateAsync()
{
   int number = Convert.ToInt32(InputTextBox.Text);
   progressBar.Minimum = 1;
   progressBar.Maximum = number;

   long result = 1;
   for (int counter = 1; counter <= number; counter++)
   {
      result = await MultiplyAsync(result, counter);
      progressBar.Value = counter;
      ResultTextBox.Text = result.ToString();
   }
}

private async Task<long> MultiplyAsync(long x, long y)
{
   await Task.Delay(1000);
   return x * y;
}
If you see the code is pretty much same. Only Async and Await are added. With async and await any one can easily write an asynchronous program. It was made so simple that I feel this can be misused. Here is the source code which demonstrates all the three approaches I mentioned above.

Download Source Code

No comments:

Post a Comment