Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Async and Await Tutorial

0.00/5 (No votes)
18 Jan 2015 1  
This tip teaches you the basic use of async and await, how threads work internally

Sample Image - maximum width is 600 pixels

Introduction

Async and await is a new feature of .NET introduced in .NET 4.0 . This feature helps you to run tasks asynchronously without blocking UI for the result. You can run multiple tasks parallelly and save time. There are three concrete scenarios where async makes sense:

  • I/O operations(Most Popular One): Async and await are useful in I/O operations like file I/O, network I/O, database I/O, (which is generally just network I/O), and web service calls. Anytime that your code is making a database call, or a web service call or a network call or talking to the file system, that can be done asynchronously while that operation is in progress .NET doesn’t have to be consuming a thread which is a CPU resource on that box while that operation is taking place. And then once the operation is finished, .NET will do the work to bring that request, and then continue it on now that you have the result from that call.
  • When we have to do multiple operations parallelly: When you need to do different operations in parallel, for example, making a database call, web service call and any calculations, then we can use async and await.
  • Long-running event-driven requests: This is the idea where you have a request that comes in, and the request goes to sleep for some time waiting for some other event to take place when that event takes place, you want the request to continue and then send a response to client. So in this case, when request comes in, then thread is assigned to that request and as request goes to sleep, then thread is sent back to thread pool and as the task completes, then it generates the event and picks a thread from thread pool for sending response (the thread sent and picked from thread pool might or might not be the same.)

One thing to keep in mind while using Async is when you are using multitasking, then it's using multiple threads for the additional operations so it will use your resource and may cause problems when you are on the Web where users hit count is very high.

Background

Let’s go through the sordid history of asynchronous programming in .NET . In .NET 1/1.1 world, we had what was called APM, the Asynchronous Programming Model, and this is the begin/end method pairs, so if you had some type of operation that when called could be done asynchronously, meaning that you could immediately return to the application, give them some token that represents whether that operation has finished or not, and then also have the caller pass in a delegate which the other side will call back when the async operation is finished, then you would expose that operation with two methods. One would be a begin method that returned an IAsyncResult, (that’s IAsyncResult, it’s an interface in the .NET base class library), and then there would be an end pair to that method which would return either void if it was the type of async method that didn’t return anything or it would return some object if you were perhaps looking up something from a database for instance, maybe a data reader or something like that.

In .NET 2.0 which is what we call Event-based asynchronous, or EAP, the Event-based Asynchronous Pattern. The idea of this is that you would call foo async after you had subscribed an event handler to the foo completed event. Now it doesn’t actually sound all that different, if you think about it. All they’re really doing is hiding the IAsyncResult from you and rather than you providing a callback, you’ve attached the callback to an event that will get raised by the object that you’ve fired the async method on.

In .NET 4, Microsoft introduced the Task Asynchronous Pattern, or TAP, some people will know this as TPL, the Task Parallel Library, and this is where we saw a new set of types, a new set of primitives introduced the framework that enabled us to get a handle on an asynchronous operation, a bit like IAsyncResult except this time it’s called Task. It represents the fact that something is running. It’s either finished already or it might finish in the future, but rather than just being a token that I then am able to pass into some other method to get the results, the task itself includes other methods that I can use to do composition. So I can say here is the task it represents this async operation; when that’s finished .continue with, go off and do this other bunch of work. And getting passed into the delegate you pass in there is the previous task that finished. If it had a result, you can just grab it off that task. So TAP introduced much nicer composition models for asynchronous programming while still utilizing the synchronization context if necessary (if you want to, you can do that), underneath the covers to do synchronization between different threads and different contexts.

Using the Code

In our code, what we are doing is we are running three tasks (a for loop, reading a RSS feed and reading the entire content of a page from web). We have two radio buttons at the top, left one is for making sync execution and the other one is for making async execution.

When you select Sync and click the single call button, then it will just run for loop synchronously and give us an execution time of approximately 01.34 seconds and in case of Async call, we get 01.44 seconds as execution time.

In case of multiple call sync, we call all the three tasks synchronously and execution time is 03.35 seconds but when we make same call asynchronously, then the execution time is 02.28.

In Asynchronous operation, the thread execution is in parallel using multiple threads so it consumes less time as compared to Sync call but in case of single call, it consumes almost the same time because we have one task and which takes very less time, so if you have only one task and its execution time is small, then you need not use async as it can create an overhead; but if your task is long running then the benefit of using async is that your interface will remain responsive.

image

Let's understand this with an example, you are going to office with your office cab and when you reaches office, then you leave the cab and go to office building. Now cab goes to office parking stand and waits for the next random call for ride. When you finish your work and make a call for the cab, then some random cab comes to pick you and takes you home and then goes back to the stand for any other call.

Now in this above mentioned case, you are the task and the cab is thread which takes you to the execution and then it goes back to the thread pool. And if some other task completes, then it uses the same thread, in this case we can use same thread multiple times instead of blocking it until the first task gets completed.

    try
    {
        cts.CancelAfter(timeToDelay);
        Task<int>[] tasksOfTasks = new Task<int>[3];

        tasksOfTasks[0] = _objDelay.DelayAsync(cts.Token);
        tasksOfTasks[1] = _objDelay.FetchFeedAsync(cts.Token);
        tasksOfTasks[2] = _objDelay.AccessTheWebAsync(cts.Token);

        await Task.WhenAll(tasksOfTasks);
        _objWatch.Stop();
        lblMultiTimeOut.Text = "Time elapsed:" + _objWatch.Elapsed;
        _objWatch.Reset();

    }
    catch (OperationCanceledException)
    {
        lblMultiTimeOut.Text = "Time Out";
    }

Microsoft has provided an interesting feature of Cancellation Token with parallel programming. You can provide a cancellation token with your async task and cancel your task if it's not responsive for a long time.

image

One catch is here you cannot cancel a running task. You can cancel if the task is in queue and not yet started or you need to check cancellation token in your task if it's true, then abort the task as we have done in our LoopRotation method.

Right hand section in the demo is useful when you want to play with timeout. You can specify the time in milliseconds and if the task is executed within the time frame, then it will display the result else it will give timeout error. In case of multiple tasks, each task is provided with the same token and if any one of them is timed out, then it will throw an OperationCanceledException.

Points of Interest

Any developer wants his/her program to be very fast responsive, so while processing your task asynchronously, you can reduce the processing time extensively.

History

  • January 16, 2015: Created

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here