Await and async in .NET 4.5 with C#

A goal for any dynamic application that is meant to handle lots of traffic is the optimal usage of server resources, including the processor. The application may need to perform processes that can be carried out on different threads. In this case it’s a waste of resources to let the actions be run one after the other on the same thread and have all other available threads lying idle. Typical examples include I/O operations and complex calculations that take long to complete that block the main thread which also handles the incoming requests and thereby reduce the scalability of the application.

There are two new keywords in .NET 4.5 that help increase the scalability of your application: async and await. Be aware that these techniques introduce threading on the server, i.e. they have nothing to do with AJAX. In this case our goal is to keep the server threads busy. Also, using these keywords alone will not automatically make your code run parallel: you’ll need to extend your solution with the Task Parallel Library (TPL).

Let’s first demonstrate the usage of TPL and async/await in a Console project. So fire up Visual Studio 2012 and create a Console app.

In the console app create a class called Operation. It is initially populated with two methods:


public class Operation
{
 public string RunSlowOperation()
 {
     Console.WriteLine("Slow operation running on thread id {0}", Thread.CurrentThread.ManagedThreadId);
     Thread.Sleep(2000);
     Console.WriteLine("Slow operation about to finish on thread id {0}", Thread.CurrentThread.ManagedThreadId);
     return "This is very slow...";
 }

 public void RunTrivialOperation()
 {
     string[] words = new string[] { "i", "love", "dot", "net", "four", "dot", "five" };
     foreach (string word in words)
     {
        Console.WriteLine(word);
     }
 }
}

We’ll print the starting and ending thread IDs of the slow operation.

Call both methods from Program.cs as follows:

public static void Main(string[] args)
        {
            Operation operation = new Operation();

            string result = operation.RunSlowOperation();
            operation.RunTrivialOperation();

            Console.WriteLine("Return value of slow operation: {0}", result);
            Console.WriteLine("The main thread has run complete on thread number {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
            
        }

…we let both operations run one after the other and also print the ID of the main thread. The result may look similar to this:
Console output

It is not surprising that we first have to wait for the slow operation to finish before the trivial task can continue. The thread ID may differ when you run this example in your VS instance. However, note that the same thread handled Main and RunSlowOperation as well.

Now we’ll let TPL enter the picture. Extend the Operation class to include the following method:

public Task<string> RunSlowOperationTask()
        {
            return Task.Factory.StartNew<string>(RunSlowOperation);
        }

…so instead of directly returning the string result we’ll only return a Task representing a method that returns a string. Edit Program.cs to call this task and get its result by using the Task.Result property as follows:

public static void Main(string[] args)
        {
            Operation operation = new Operation();

            Task<string> result = operation.RunSlowOperationTask();
            operation.RunTrivialOperation();

            Console.WriteLine("Return value of slow operation: {0}", result.Result);
            Console.WriteLine("The main thread has run complete on thread number {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
            
        }

When you run this then you will see that the slow operation did not block the main thread and the trivial operation could continue:
Console output

You’ll notice that the programme was carried out on two threads: one for the main thread and one for RunSlowOperation().

We’ll now include async and await to increase the efficient usage of our resources.

We can include the keyword async to method to make it asynchronous. An async method must have ‘await’ somewhere in its body otherwise the VS will complain. The await keyword indicates that the task it denotes can be suspended until some other task is complete. While the async method is suspended the caller is free to continue with what it is doing. This means that the thread that starts an async method may jump out of it at the await keyword and a different thread will jump in again and continue where the previous thread left off.

Async methods should always return a Task or a Task of T. The name of the async method should end with ‘Async’ to indicate to the caller that it is in fact an asynchronous method. The await keyword can occur more than once within the method body.

Extend Operation.cs to include the following method:

public async Task<string> RunSlowOperationTaskAsync()
        {
            Console.WriteLine("Slow operation running on thread id {0}", Thread.CurrentThread.ManagedThreadId);
            await Task.Delay(2000);
            Console.WriteLine("Slow operation about to finish on thread id {0}", Thread.CurrentThread.ManagedThreadId);
            return "This is very slow...";
        }

Note that Thread.Sleep was replaced by Task.Delay(2000). Thread.Sleep blocks the thread whereas Task.Delay represents a work that will block the thread for two seconds. At that point the thread that started the method may jump out of the method and let a different thread complete it to completion when the Task has finished.

Modify Program.cs as follows:

public static void Main(string[] args)
        {
            Operation operation = new Operation();

            Task<string> result = operation.RunSlowOperationTaskAsync();
            operation.RunTrivialOperation();

            Console.WriteLine("Return value of slow operation: {0}", result.Result);
            Console.WriteLine("The main thread has run complete on thread number {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
            
        }

The output may look as follows:

Console output

We have some differences compared to the previous case:

  • The slow operation starts on the same thread as Main whereas it started on its own thread before
  • The slow operation completed on a different thread from the one that started it
  • The main thread jumped out of the long running method and continued with the trivial method of printing the string array elements

When the main thread encountered the await keyword it ‘knew’ that it could leave the long running method and let a different thread take over and finish it. The beauty of this is that the new thread that took over from the main thread will have the necessary context data available: HTTP context, identities, culture settings. The thread synchronisation job is taken care of by .NET behind the scenes.

Note that this behaviour is not guaranteed to occur: in some cases, such as Silverlight, the UI thread must stay constant. However, the benefit is that the UI will not freeze when it encounters a long running method: it can still stay active and react to user inputs.

To summarise:

  • Async and await help make the usage of processing threads more efficient
  • They will not make your code run parallel without the TPL
  • The thread that started an async method may not be the same as the one that finished the method
  • The available threads will not just lie idle and block incoming requests while waiting for a task to finish

In the next blog we’ll look at async/await in MVC4.

View the list of MVC and Web API related posts here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

16 Responses to Await and async in .NET 4.5 with C#

  1. QuantumCD says:

    Nice tutorial! Threading is so nice in C#/.NET. C++ makes everything so… messy at times. At least that’s changing with better libraries and stuff.

  2. TryingHard says:

    Really helpful article! I am now getting this stuff and working through this code in Visual Studio 2013 helped a lot. However, two suggestions from someone who approached the async/await/Task topic from “scratch” (not knowing anything whatsoever about it, and not even having done much with threading in C# in general). There were several things that hindered my full understanding. (Try to make yourself think like someone that knows nothing about the topic 🙂

    (1) The use in this tutorial, as well as almost every other one I’ve seen, in the async Task example (third and last example in this tutorial) of “await Task.Delay(nnnn)”. To some beginners this may not be very clear, because it is somewhat contrived code, not a “real world” example. Now of course it is necessary to do this just to make the code actually execute properly for those who try to follow along making it work in Visual Studio themselves – but I would suggest at least doing something like the following on that line of code, using a comment to make what is happening more understandable:

    await Task.Delay(2000); // imagine this is invoking an async method of a WCF service that takes 2 seconds to return its result, for example: await serviceClient.SomeMethodAsync();

    Actually, this reinforces TWO sub-concepts, not only showing what “real” code might look like (which is always helpful for beginners), but also, simply the fact that the “lowest-level” operation that is taking place in the scenario, really needs to itself be a TRUE async implementation that returns a Task or Task object, such as the async methods that can be generated by Visual Studio when creating a WCF service, for example. That concept itself was also not clear to a beginner like me, as can be seen in my exchange with another great author, Stephen Cleary, at

    http://blog.stephencleary.com/2012/02/async-and-await.html

    (see my recent blog entries on that page under name “Grateful”)

    (2) The other fine point that I wasn’t getting (and haven’t even seen anyone discuss anywhere, I had to figure this out just from trial and error and doing F11’s following the code execution through in debug mode) is the following concept: Yes we are doing asynchronous operations and parallel operations etc etc. But at some point, we are going to want to utilize the RESULT of whatever that asynchronous operation is (if there IS a result, yes we can do “fire-and-forget” type of things but that is a different discussion). Hence the line of code in your examples:

    Console.WriteLine(“Return value of slow operation: {0}”, result.Result);

    is where we utilize/refer to the result of the

    Task result = operation.RunSlowOperationTaskAsync();

    execution. And – this being the crucial point – it is actually the act of referring to “result.Result”, the string value being returned by the Task, that makes the code come back to THAT line of code

    Console.WriteLine(“Return value of slow operation: {0}”, result.Result);

    and wait (in the general sense of the word “wait”) for the completion of the RunSlowOperationTaskAsync method!

    If (and this is what I discovered by accident while pounding on this stuff, but which actually helped me to understand it better) one simply comments out that line of code

    Console.WriteLine(“Return value of slow operation: {0}”, result.Result);

    then here is what the output of the program looks like:

    i
    love
    dot
    net
    four
    dot
    five
    The main thread has run complete on thread number 9
    Slow operation about to finish on thread id 11

    What happened? Well, by NOT referring to the “result.Result” variable, we essentially made it as if we DIDN’T care about any results, or what happened with, the RunSlowOperationTaskAsync method. Not that this is what we would normally do – except as mentioned above, in one way we have produced a kind of “fire-and-forget” operation that essentially and merely just executes on another thread, as Stephen Cleary pointed out to me in the discussion I had with him on his blog.

    But by not referring to the “result.Result” variable, we just blow through any/ALL other code that comes after the

    Task result = operation.RunSlowOperationTaskAsync();

    line of code, in this case, executing the RunTrivialOperation() method AND showing that last Console.WriteLine of “The main thread has run complete on thread number 9”.

    After which, the ‘puter gets to executing the code inside the RunSlowOperationTaskAsync method on another thread, thread 11.

    Now I know that all probably seems fairly elementary to you, Andras, but like I said, to a beginner this is a crucial concept because it points out how it is that the actual program control hops around in terms of flow of control and threads, and how it is dependent on referring to the result.

    In your article I think it might be helpful to have a 4th step in which you instruct the reader to comment out the

    Console.WriteLine(“Return value of slow operation: {0}”, result.Result);

    line of code, show the output, and explain what is happening and why. It wasn’t until I did that that I really understood the fundamental use case the way it needs to be understood. After all, what’s the use of executing an operation (that does in fact return some kind of data) asynchronously if you don’t make use of the data it returns (eventually)?

    Again, this is probably a point that seems obvious to those who are not beginners 🙂

    But, it is instructive that it is the very making-use-of-that-returned-data that makes it such that the entire async/await/Task mechanism and paradigm works the way it SHOULD work, IN ACTUAL PRACTICE. And it was not understanding that concept that was making it hard for me to really understand the stuff. (In some ways I was trying to make everything too hard, in other ways I wasn’t grasping things like this that seem like simple points.)

    But in any case, I hope you get the point I am trying to make (and maybe this info will be helpful to other beginners who may be fuzzy on the basic async/await/Task paradigm like I was). Thanks Andras for your great blogs and tutorials!

  3. Ravi says:

    nice one

  4. Joe says:

    will it be possible the string ‘Slow operation about to finish on thread id ..’ will be shown inside the ‘RunTrivialOperation()’ strings, instead of after it?

  5. Hidalgo says:

    If you don’t mind, I would like to ask a conceptual question. I have an ASP.NET application where on Submit some email messages are sent to a one or more persons. This process, of sending emails, sometimes delays the process and a user has to wait for the Acknowledgement page. Would converting the method that sends emails into the “async” method be logical approach of speeding up the user experience?
    Thank you in advance.

    • Andras Nemes says:

      No, I don’t think it would make the process any faster. Await and async are used to optimise the usage of threads in a multi-user scenario, like on a web site, so that the system can handle more users. However, each user will still need to wait for the underlying process to execute regardless of which thread it is executed on. If you want to make the process faster then you’ll need to optimise the code, get a stronger server or put the email sending process on a different thread and not wait for it to finish if it’s not important for the end user. That’s a fire-and-forget strategy. //Andras

      • Hidalgo says:

        Thank you very much for the reply. I see that I would have to learn how to “send the email process on a different thread and not wait for it to finish” (as it is not important, as you correctly assumed). I was mistakenly thinking that async does exactly that.
        Again, I appreciate your reply.

      • Andras Nemes says:

        You’re welcome. That’s not a difficult feature to implement, you’ll need to look into the Task library. You may as well start on this blog on this page: https://dotnetcodr.com/task-parallel-library/

        //Andras

  6. Hidalgo says:

    Andras, thank you very much!

  7. Naveen says:

    incase of RunSlowOperationTask()—–started and ended thread is same.
    but
    incase of RunSlowOperationTaskAsync–
    started with Main Thread id and ended with new thread it.

    How we benefited with async and await ? please expalin…waiting for reply..

  8. Awesome blog…keep writing.

  9. Pingback: Long Running Task C# – Lancer Pro Ltd

Leave a reply to Andras Nemes Cancel reply

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.