In this article I want to give a simple example for how to use the async await keywords in C# to create asynchronous background tasks.

Writing multi-threaded or asynchronous code has traditionally always been very hard to get right but is something that is needed to help keep our applications responsive and to avoid performance bottlenecks. C# 5 introduced a simplified model for doing asynchronous programming with the introduction of 2 new keywords, async and await.

If you specify that a method is an asynchronous method by using an async modifier, you enable the following two capabilities.

  • The marked async method can use the await keyword to designate suspension points. The await operator tells the compiler that the async method can’t continue past that point until the awaited asynchronous process is complete. In the meantime, control returns to the caller of the async method. The suspension of an async method at an await expression doesn’t constitute an exit from the method, and finally blocks don’t run.

  • The marked async method can itself be awaited by methods that call it.

An async method typically contains one or more occurrences of an await operator, but the absence of await expressions doesn’t cause a compiler error. If an async method doesn’t use an await operator to mark a suspension point, the method executes as a synchronous method does, despite the async modifier. The compiler issues a warning for such methods.

Asynchrony is essential for activities that are potentially blocking, such as when your application accesses the web or a file system. Access to a web resource, for example, is sometimes slow or delayed. If such an activity is blocked within a synchronous process, the entire application must wait. In an asynchronous process, the application can continue with other work that doesn’t depend on the web resource until the potentially blocking task finishes.

Lets take a look at a simple example.

using System;
using System.Threading.Tasks;

namespace AsyncAwaitExample
{
    class Program
    {
        static void Main()
        {
           var demo = new AsyncAwaitDemo();
           demo.DoStuff();

           while (true)
           {
               Console.WriteLine("Doing Stuff on the Main Thread...................");
           }
        }
    }

    public class AsyncAwaitDemo
    {
        public async Task DoStuff()
        {
            await Task.Run(() =>
            {
                LongRunningOperation();
            });   
        }

        private static async Task<string> LongRunningOperation()
        {
            int counter;

            for (counter = 0; counter < 50000; counter++)
            {
                Console.WriteLine(counter);
            }

            return "Counter = " + counter;
        }
    }
}

This program contains a class called AsyncAwaitDemo. In this class there is a public method called DoStuff() which launches a long running operation called LongRunningOperation(). This method is marked with the async keyword. For this simple example, the LongRunningOperation() method just counts to 50000 and prints the counter to the console.

Back in our Main() method, after executing the DoStuff() method we then go into an infinite while loop that prints to the console. When you run the program you see something like the following.

Here the code is running asynchronously.
Here the code is running asynchronously.

What you see here is that the infinite while loop is executing, but the long running task we kick off is also running in the background and counting up to 50000.

Lets modify the code slightly by removing the Task.Run, so that the method looks like the following :

        public async Task DoStuff()
        {            
            LongRunningOperation();         
        }

If we then run the program we get the following.

Here the code is running synchronously.
Here the code is running synchronously.

Because we have removed the line with the await keyword, the LongRunningMethod() now runs synchronously, so the counter will first count up to 50000 and then the code will go into the while loop.

Avoid Async Void

There are three possible return types you can use for async methods:

  • Task
  • Task<T>
  • void

The main return types for async methods are just Task and Task<T>. When you are converting from synchronous to asynchronous code, any method returning a type becomes an async method returning Task<T>, and any method returning void becomes an async method returning Task.

Async methods that return void have a specific purpose and that is to make asynchronous error handlers possible, but async void methods have different error handling semantics. When an exception is thrown in an async Task or async Task<T> method, that exception is captured and placed directly on the Task object. With an async void method, there is no Task object involved, so any exceptions thrown out in an async void method will be raised directly on the SynchronizationContext that was active when the async void method started. For more information I recommend reading the following MSDN article that has some good examples.

Wrapping Up

In this simple example we used the Task.Run() method to incorporate the await keyword into the code, but .NET framework also provides many async compatible API’s that you can also use with async await. You can recognize these members by the “Async” suffix that’s attached to the member name and a return type of Task or Task. For example, the System.IO.Stream class contains methods such as CopyToAsync, ReadAsync, and WriteAsync alongside the synchronous methodsCopyTo, Read, and Write.

This is a nice and simple example that I hope help you to understand the usage of async / await. It is a flexible and powerful feature of C# 5 and above that should make it much easier for you to write responsive applications.

Advertisements

11 comments

  1. Hi. Thanks for the suggestion. I have amended the code, written a little explanation and linked to the MSDN article.

  2. I think this line is backward: “any method returning a type T becomes an async method returning Task, and any method returning void becomes an async method returning Task.”

  3. In my Visual Studios 2013 and 2015, the LongRunningOperation method got this warning:
    “This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls, or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.”

    However, when I ran the program, it did run asynchronously.

    In order to get the warning message to go away, I changed the DoStuff method to include the code in the LongRunningMethod.
    When run, the program had the same results, but Visual Studio did not have the warning. Do you think that this is a bug with Visual Studio 2013, or is there something else going on over here?

    My DoStuff was changed to like this:

    public async Task DoStuff2()
    {
    await Task.Run(() =>
    {
    int counter;

    for (counter = 0; counter < 50000; counter++)
    {
    Console.WriteLine(counter);

    //if (counter % 5 == 0)
    // Console.ReadLine();
    }
    });
    }

  4. if you remove async await from everywhere the result remains the same:

    namespace AsyncAwaitExample
    {
    class Program
    {
    static void Main()
    {
    var demo = new AsyncAwaitDemo();
    demo.DoStuff();

    while (true)
    {
    Console.WriteLine(“Doing Stuff on the Main Thread……………….”);
    }
    }
    }

    public class AsyncAwaitDemo
    {
    public void DoStuff()
    {
    Task.Factory.StartNew(LongRunningOperation);
    }

    private static string LongRunningOperation()
    {
    int counter;

    for (counter = 0; counter < 50000; counter++)
    {
    Console.WriteLine(counter);
    }

    return "Counter = " + counter;
    }
    }
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s