Asynchronous Programming in C# (.NET Framework 4.5 or Higher)

Asynchronous Programming

Asynchronous operation means that the operation runs independent of main or other process flow. In general c# program starts executing from the Main method and ends when the Main method returns. In between all the operations runs sequentially one after another. In Synchronous, one operation must wait until its previous operation finishes. Let’s see following code:

[code language=”csharp”]
static void Main(string[] args)
{
string a = DoTaskOne();
DoTaskTwo();
}

static string DoTaskOne()
{
string result = "This is Task One"
return result;
}

static void DoTaskTwo()
{
//do something here
}
[/code]

Method “DoTaskTwo” would not be started until “DoTaskOne” finishes. In other words method “DoTaskOne” blocks the execution as long it takes to finish.

In asynchronous programming a method is called that runs in the background and the calling thread is not blocked. After calling the method the execution flow immediately backs to calling thread and performs other tasks. Let’s see following code:

[code language=”csharp”]
static async void Main(string[] args)
{
Task<string> task1 = DoTaskOne();
Task task2 = DoTaskTwo();

//In async method must have at least one keyword await
await Task.WhenAll(task1, task2);

string a = task1.Result;
task2.Result;
}

static Task<string> DoTaskOne()
{
string result = "This is Task One"
return Task.FromResult(result);
}

static Task DoTaskTwo()
{
//do something here
return Task.FromResult(0);
}
[/code]

Task-based Asynchronous Pattern

First of all we need an asynchronous method that returns Task or Task. We can create Task by following ways:

  1. Task.Factory.StartNew method: Prior to .NET 4.5 (in .NET 4) this was the primary method to create and schedule a task.
  2. Task.Run or Task.Run Method: From .NET 4.5 this method should be used. This method is sufficient for most of the common cases.
  3. Task.FromResult method: If the result is already computed, we can use this method to create a task.

Task.Factory.StartNew has still some important uses for advance scenario. Please see the link for more information: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx

“async” and “await” keywords

.NET framework introduced two new keywords to perform asynchronous programing: “async” and “await”. To use “await” keyword within a method we need to declare the method with “async” modifier. “await” keyword is used before calling an asynchronous method. “await” keyword suspends further execution of the method and control is return to the calling thread.

The “async” modifier can only be used with methods returning a Task or void. It cannot be used with the entry point of a program, the Main method.

We cannot use await keyword before all the methods. To use “await” the method must have to return “awaitable” type. Following are the types that are “awaitable”:

  1. Task
  2. Task<T>

Creating and awaiting for a Task

Let’s assume that we have a method that is synchronous

[code language=”csharp”]
static string Greeting(string name)
{
return string.Format("Hello, {0}", name);
}
[/code]

To access this method asynchronously we have to wrap it with an asynchronous method. Let’s assume the name is “GreetingAsync”. It is a convention to add “Async” suffix to the name of an asynchronous method.

[code language=”csharp”]
static Task<string> GreetingAsync(string name)
{
return Task.Run(() => Greeting(name));
}
[/code]

Or we can do this:

[code language=”csharp”]
static Task<string> GreetingAsync(string name)
{
return Task.FromResult(Greeting(name));
}
[/code]

Now we can call the asynchronous method GreetingAsync by using the await keyword

[code language=”csharp”]
static async void CallWithAsync()
{
string result = await GreetingAsync("Andi");
Console.WriteLine(result);
}
[/code]

When “CallWithAsync” method is called it starts executing like regular synchronous method until it reaches “await” keyword. When it reaches to the “await” keywords it poses execution for the method and start waiting for “GreetingAsync(“Andi”)” method to be finished. In the meantime the control returns to the caller of “CallWithAsync” method and the caller can do its other task as usual.

When “GreetingAsync(“Andi”)” method finishes, “CallWithAsync” method resumes its other task after “await” keywords. In this case it executes the code “Console.WriteLine(result)”

Awaiting for multiple asynchronous methods

Let us look at the following code:

[code language=”csharp”]
static async void CallWithAsync()
{
string result1 = await GreetingAsync("Andi");
string result2 = await GreetingAsync("Budi");
Console.WriteLine(result1);
Console.WriteLine(result2);
}
[/code]

Here we are awaiting for the two calling sequentially. Second call of the “GreetingAsync(“Budi”)” will be started after finishing the first call “GreetingAsync(“Andi”)”. If “result1” and “result2” of the above code are not dependent, then the sequential “awiting” is not a good practice.

In that case we can simply call the methods with “await” keywords for them in a single place by combinators. In that case both the method call can be executed in parallel.

[code language=”csharp”]
static async void CallWithAsync()
{
Task<string> task1 = GreetingAsync("Andi");
Task<string> task2 = GreetingAsync("Budi");

await Task.WhenAll(task1, task2);

Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}",
task1.Result, task2.Result);
}
[/code]

Here we use Task.WhenAll combinator. Task.WhenAll creates a task that will complete when all of the supplied tasks have completed. Task class has another combinator. Task.WhenAny, that will complete when any of the supplied tasks have completed.

Handling Exceptions

We have to put “await” code blocks inside a try block to handle the exception of the method.

[code language=”csharp”]
static async void CallWithAsync()
{
try
{
string result = await GreetingAsync("Andi");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
}
}
[/code]

for multiple asynchronous methods we can do this:

[code language=”csharp”]
static async void CallWithAsync()
{
Task taskResult = null;
try
{
Task<string> task1 = GreetingAsync("Andi");
Task<string> task2 = GreetingAsync("Budi");

taskResult = await Task.WhenAll(task1, task2);

Console.WriteLine("Finished both methods.\n Result 1: {0}\n Result 2: {1}",
task1.Result, task2.Result);
}
catch (Exception ex)
{
Console.WriteLine("handled {0}", ex.Message);
foreach (var innerEx in taskResult.Exception.InnerExceptions)
{
Console.WriteLine("inner exception {0}", innerEx.Message);
}
}
}
[/code]

Reference

Topaz Moderato has written 14 articles

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>