CodeSteps

Python, C, C++, C#, PowerShell, Android, Visual C++, Java ...

C# – Asynchronous programming – async and await

Usually, when we run the C# code, each statement executes synchronously; that means, one after another statement, executes sequentially. But, how do we instruct to run the code asynchronously? For example, watching a video while it is downloading; instead of waiting for the video to be completely downloaded. Of course, we call it streaming media; just for this example, I am considering this as an asynchronous operation.

Another well-known example of the asynchronous operation is, the application window will allow interaction even though some background operations are in progress.

We use threads for asynchronous operations. Creating and Managing the Threads require more code to be added to the Program. To simplify this, and instruct to run the code asynchronously; C# has introduced async & await keywords.

async keyword instructs the compiler that the declared method has await statements inside, and which has asynchronous operations to execute. async method needs to have a await statement to instruct to run the code asynchronously. Otherwise, the statements within async method will execute synchronously.

You need to understand one important thing here is, when we use these keywords, we are instructing to execute the statements in async method asynchronously. The statements may or may not execute asynchronously; this is purely depending on the way you use statements inside an async method.

There are different ways we can achieve asynchronous execution of code. Through this Article, we are going to discuss it with the help of async, await keywords & Task class.

async modifier

async modifier instructs the compiler that, the function with this modifier has an await statements inside; which has asynchronous operations to execute. We can use this modifier with lambda expressions and methods (both named and anonymous methods).

Can we use this async keyword with all the methods? No. This modifier can be used ONLY with the methods; whose return type is Task, Task<T> or void. Otherwise, you will see the below Error message, when you build your C# program.

Error 1 The return type of an async method must be void, Task or Task<T>

From C# 7.0; async methods can return any type that has an access GetAwaiter() method.


And also, older versions of C# are not allowed to use this modifier with Main method. You will get the below error message when you attempt to use async modifier with Main method; or an entry point.

Error 1 'Async_Await_Demo.Program.Main(string[])': an entry point cannot be marked with the 'async' modifier

Within the asynchronous methods, usually, the statements will run asynchronously. By mentioning await statement in an aysnc method; we are instructing to run the statements asynchronously. Otherwise, the statements within async method, execute synchronously. How it manages? This is completely behind the scene of async & await keywords. And as I mentioned above, you need to be cautious when you use statements within the async method; otherwise, the statements may not run asynchronously; even though you use both async & await keywords.

What exactly await will do? That’s what we will discuss in the below section.

If you write the asynchronous method, without await statements within it; the compiler will throw the below Warning message.

Warning 5 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.

await keyword

The await keyword inserts the suspension point in the execution of the asynchronous method until the awaited Task completes. That means the statements after await statement will not execute until the associated Task completes its execution. But the program control can go back to the function from where this asynchronous method is called; which allows the execution of the next statements in the called function. This is possible when the associated Task will execute in asynchronous mode.

Doesn’t it clear? Read it carefully one more time, the above paragraph. The await operator simply instructs to suspend the execution of the next statements, within the async method, until the associated Task completes. Once the Task is completed, the asynchronous method resumes the execution where it was suspended; that means, the statements after await statement will continue to execute.

Does it mean, async method will run in a separate thread? Not necessarily. That is the beauty of this feature. Associated Task will execute in the current thread or in a separate thread. A separate thread, doesn’t mean a new thread; it is a thread from Thread Pool. .Net framework manages this thread pool, which contains managed threads, to allow it to execute asynchronous operations.

Does it execute in an asynchronous way, every time when we use Tasks? Not really. The tasks may or may not run asynchronously. This is completely depending on the way you write the program code. Through this article, we are going to achieve this by using Task’s Run() & Delay() methods. Task classes are useful for asynchronous operations.

The important thing you need to remember is, you can’t use await keyword with all the statements; you can use this, only with the statements which return Task or Task<T> type or void types (this is for Event handlers). From C# 7.0, we can use these with any type that has an accessible GetAwaiter() method. 

That said, the below statement is invalid; if SayHello() doesn’t return above mentioned types;

await SayHello();

The compiler will throw the below Error message;

Error 1 Cannot await 'void'

Task and Task<T> are the classes defined in System.Threading.Tasks namespace, useful for asynchronous operations. It has a Run() method, through which we can instruct the portion of the code or function to run in a separate thread; a thread pool’s thread For example, the statement looks like below;

Task.Run( () => SomeFunction() );

From the above statement, SomeFunction() will execute in a separate thread, a thread in a thread pool. We can verify whether the Thread is the thread pool’s thread or not; by simply adding the below statement. It displays True, when it is the thread pool’s thread; otherwise, it displays False.

Console.WriteLine(System.Threading.Thread.CurrentThread.IsThreadPoolThread.ToString());

Maybe, I will write a separate article to discuss Task and Task<T> classes. In our sample program, we are using Task & Task<T> classes to run a function in an asynchronous way.

Complete working code

Let’s put it all together and our code looks like below. This code was tested in Windows 7 Operating System and developed using Visual Studio 2012 IDE.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Async_Await_Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Async demo, one example with Task.Delay() function
            Console.WriteLine("====== Async demo ======");
            Task task1 = SomeAsync();

            SayHello();

            Console.WriteLine("Waiting... async function to return.");
            task1.Wait();            

            // Async demo, another example with Task.Run() function
            Console.WriteLine("\n\n====== Async demo - usually run in a separate thread ======");
            Task task2 = AnotherAsync();

            SayHello();

            Console.WriteLine("Waiting... async function to return.");

            Console.WriteLine(">>> Random Number: " + task2.Result);
           
            task2.Wait();
        }

        static async Task SomeAsync()
        {
            Random r = new Random();
            
            await Task.Delay(5000);

            Console.WriteLine(">>> Random number: " + r.Next());            
        }      

        static async Task AnotherAsync()
        {
            // Instruct to run some action in a thread pool's Thread.
            int result = await Task.Run(() => GetRandomNumber());

            return result;
        }

        static int GetRandomNumber()
        {            
            Random r = new Random();

            for (UInt32 i = 0; i < System.UInt32.MaxValue; i++);
            
            return r.Next();
        }

        static void SayHello()
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Code walk-through

Now, this is the time to walk through the code. It has two async methods; SomeAsync & AnotherAsync. And it has two normal functions; SayHello & GetRandomNumber.

SomeAysnc is an async method, which displays the new random number. But, before it displays the random number; it simply delays the execution of the function for 5 seconds, and gives back the control to the called function to allow it to execute the rest of the statements. It waits for, 5 seconds; before it executes the next statement after await. This is one example of an asynchronous operation.

AnotherAsync method is an async method we have developed, and it simply calls another method GetRandomNumber, and returns the result of the function; which is a newly generated random number. But, it requests to execute the GetRandomNumber function, in a thread. And await statement will suspend the execution of the async method until the thread completes execution. Meanwhile, the control goes back to the called function (in this case, it is Main); and starts executing the statements mentioned after the async method.

GetRandomNumber simply returns the random number. I just keep it busy, by putting a long loop to give the feeling that some lengthy operation is in progress. 🙂

SayHello simply displays a message.

The important thing, we need to observe here is; the way the functions are executed and the results were shown. We called SayHello after the async methods. As the async methods executed asynchronously, you will see the Hello message before the completion of async methods; in normal cases, SayHello will execute ONLY when all the statements (which are mentioned before this method) are executed.

This has proved that our program is executing asynchronously.

Another important thing is, we have called Wait() methods of the Task; to keep the Main method to wait until the completion of the async methods. This is important; because the chances are there, the Program terminates before the completion of async methods.

(Raju)

C# – Asynchronous programming – async and await

One thought on “C# – Asynchronous programming – async and await

Leave a Reply

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

Scroll to top