Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / C#
Tip/Trick

Asynchronous Programming in C# 5.0 using async and await

Rate me:
Please Sign up or sign in to vote.
4.74/5 (35 votes)
14 May 2013CPOL4 min read 233.7K   4.4K   83   11
A light article about a new feature in C# 5 and .NET 4.5

Introduction

In a previous article posted in March 2010, “Extending the IAsyncResult Pattern for Multiple Parameter Function Calls”, I showed that I had to implement IAsynchResult in order to fix a problem I encountered by then which I would not have to, if this feature had been supported by then.

I am writing now about a new feature that is introduced by C# 5.0, using two keywords async and await.

Why It’s Important

As you all know, Asynchronous and Parallel programming is such a very important style that tends mainly to perfect the responsiveness of our applications. .NET has always been trying to support that style since its very first release and there have always been many new features in each release and introduction of new ways of asynchrony. All these features are out of the scope of this article but there are so many resources talking neatly and verbosely about them and describing their use in details.

However, we developers used to write methods, I would say synchronous methods and try to call them asynchronously, through many ways (Thread, ThreadStart, ThreadPool, BackgroundWorker, etc.), but writing asynchronous methods in nature was somehow hard to do and maintain.

The feature I am to talk about enables us to create asynchronous methods so easily on the fly, as a matter of fact, it helps us to change our traditional synchronous methods into asynchronous ones.

The Task Class

The feature can be summarized by the following example where we changed the method to an asynchronous one inherently or by nature, simply by changing the return type.

Let’s consider a long running method:

C#
public static IEnumerable<int> getPrimes(int min, int count)
{
    return Enumerable.Range(min, count).Where
      (n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i =>
        n % i > 0));
}

Depending on the parameters min and count, this method can take a long time.

One way to make it asynchronous is to simply change the return type as in the following example:

C#
public static Task<IEnumerable<int>> getPrimesAsync(int min, int count)
{
     return Task.Run (()=> Enumerable.Range(min, count).Where
      (n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i =>
        n % i > 0)));
}

In the example above, please notice that we changed the name of the method itself by adding Async and that is the convention to be followed.

The return type is Task in case it was void and Task<T> where T is the return type of method.

What is Task?

Task is simply an implementation to IAsynchResult, that’s why I had to mention the article I wrote before or the problem I encountered and the solution I had to reach.

Now when a method returns Task<T> then it is awaitable and that means you can call it using the keyword await, and that means whenever you call it using await, the execution control will come back to you immediately and there will be no impact on the responsiveness of your application.

Let's see how we call these methods above:

C#
private static void PrintPrimaryNumbers()
{
    for (int i = 0; i < 10; i++)
        getPrimes(i * 100000 + 1, i * 1000000)
            .ToList().
            ForEach(x => Trace.WriteLine(x));
}

PrintPrimaryNumbers() is a method that we can call directly and traditionally, I am calling it here 10 times, it will be called consequently and we will see how long it will take to finish.

C#
private static async void PrintPrimaryNumbersAsync()
{ 
    for (int i = 0; i < 10; i++)
    {
        var result = await getPrimesAsync(i * 100000 + 1, i * 1000000);
        result.ToList().ForEach(x => Trace.WriteLine(x));
    }
}

Whilst PrintPrimaryNumbersAsync() is decorated by the keyword async and it calls getPrimesAsync asynchronously.

Once it calls, the execution immediately returns to the caller (the main thread).. and once any of the other threads is done, it will get the control back (in our case, write the primary numbers in found in the range supplied).

To make the picture clearer, run and minimize the range like in the source files attached.

Now let’s see the main function:

C#
static void Main(string[] args)
{

    DateTime t1 = DateTime.Now;
    PrintPrimaryNumbers();
    var ts1 = DateTime.Now.Subtract(t1);
    Trace.WriteLine("Finished Sync and started Async");
    var t2 = DateTime.Now;
    PrintPrimaryNumbersAsync();
    var ts2 = DateTime.Now.Subtract(t2);

    Trace.WriteLine(string.Format(
      "It took {0} for the sync call and {1} for the Async one", ts1, ts2));

    Trace.WriteLine("Any Key to terminate!!");
  
}

Can you tell the difference between ts1 and ts2?

Here is the result:

Finished Sync and started Async

It took 00:32:16.1627422 for the sync call and 00:00:00.0050003 for the Async one

If you choose a small range for test, you can see something like:

Image 1

It is very important to notice that the time measured here is not the time that took the async operation to complete, it is the time that took the async operation to kick in or start, but it did not block the main thread and that was the nice catch about it, if you wait for this and waited for the results to come and then measure the time then you will know the time accurately taken by the async call.

Usually we use Task.WaitAny(...) or Task.WaitAll(...) to keep the main thread waiting till the asynchronous calls to finish, and that is what I have not done here and maybe should have.

Console.ReadLine() will hold the main thread till you click any key, expecting that you will wait to see the results before you terminate it.

In short, the example shows you that you can easily run asynchronous calls without blocking the main thread but it did not show how to get the results in an adequate manner.

Summary

.NET platform 4.5 has made some revolutionary technique in the asynchronous programming and gave up some old techniques that are now called obsolete (BackgroundWorker, Event Asynchronous Programming, Asynchronous Programming Model APM).

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
United States United States
I graduated as an electronic engineer at 2000, and I have been working in software development ever since.
Interested mainly in .NET technologies.

Comments and Discussions

 
PraiseClear Pin
Member 1362148213-Jan-18 7:43
Member 1362148213-Jan-18 7:43 
GeneralRe: Clear Pin
Assil13-Jan-18 12:24
professionalAssil13-Jan-18 12:24 
GeneralMy vote of 3 Pin
pyanfur8-Apr-15 14:18
pyanfur8-Apr-15 14:18 
GeneralVery Nice Pin
Member 1119543323-Dec-14 20:12
Member 1119543323-Dec-14 20:12 
GeneralRe: Very Nice Pin
Assil23-Dec-14 23:03
professionalAssil23-Dec-14 23:03 
AnswerMy Vote 5 Pin
govind giri30-Jul-13 21:26
govind giri30-Jul-13 21:26 
GeneralRe: My Vote 5 Pin
Assil22-Jun-14 2:41
professionalAssil22-Jun-14 2:41 
GeneralMy vote of 5 Pin
Oshtri Deka11-Jun-13 23:25
professionalOshtri Deka11-Jun-13 23:25 
GeneralRe: My vote of 5 Pin
Assil22-Jun-14 2:40
professionalAssil22-Jun-14 2:40 
BugOMG Pin
springy7612-May-13 22:25
springy7612-May-13 22:25 
GeneralRe: OMG Pin
Assil12-May-13 23:21
professionalAssil12-May-13 23:21 
Thank you so much springy76..
As a matter of fact, I am not quite satisfied about the attached example..
An updated one will show clearer results with..
But I hope the main Idea is clear for everyone who reads this article.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.