(C# Language) Asynchronous Task Programming

An application is often required to make database access, perform file read and write or contact internet for communication. All these tasks involve time consuming operations that make the main thread too busy. This causes the application to hang and freeze while the main thread waits for a large file to download. The solution to this problem lies in asynchronous task programming. A potentially long and time consuming operation can be run in parallel in such a way that the UI (user interface) remains responsive and, possibly, provides a progress feedback to the user. Let's explore it in this tutorial!
(Rev. 19-Mar-2024)

Categories | About |     |  

Parveen,

Table of Contents (top down ↓)

What is a Task?

A function intended to run asynchronously should be marked as async modifier and it should return a Task if the return type is void, and Task<T> if it returns a data of type T.

For example, a function that makes an internet communication, or disk access or database communication is marked as async, and it returns a Task or Task<T> depending on the type of data returned.

Create a C# console application for the latest version of .NET Core.

Open the solution explorer and add a class called MyClass.

And add a function called async Task int my function. It has been marked with the modifier async and it returns an int wrapped in a Task. Both async and Task signal that this function is intended to run in asynchrononous mode.


// WATCH VIDEO FOR A BETTER EXPLANATION 

internal class MyClass
{
  public async Task<int> MyFunction()
  {
    Console.WriteLine("2. TASK: task started ...");

    int i = 0;

    // any work 
    for (int x = 0; x < 10; x++)
    {
      i++;
    }

    // runs synchronously till an await is met 
    await Task.Delay(5000);

    Console.WriteLine("7. TASK: task completed after 5s returning data...");

    return i;
  }
}

Come to the program.cs file and create an instance of the class MyClass.

Print a message that announces that we are about to start an asynchronous work.

Make a call to MyFunction and obtain the Task object. This will start the execution of MyFunction.

Video Explanation (see it happen!)

Please watch the following youtube video:

Inside async function

Now let's come back to MyFunction and add a message that this function has started its execution.

Next some variable is created, and then a loop is started.

Remember that the execution is still synchronous so far.

Next let's add an artificial delay of 5 seconds - await Task.Delay(5000);. In a real scenario this delay is caused by some disk access, database access or by network or by some image processing function, anything. The await keyword tells the compiler to suspend execution of the currently executing function - MyFunction. Let's see what happens here -

  1. It uses a CPU trick to return back to the program.cs file.
  2. A new thread is NOT created. Multi-threading doesn't occur here. It is an optimal use of the free CPU slots.
  3. The calling thread is NOT paused here. Nothing stops. The control is returned back to the program.cs file while the 5 second period is counted.

Back to Program.cs file

Come back to the program.cs file and print a message that we are back. Notice that we have numbered the messages in an expected sequence.

While the previous is code is counting its 5 seconds, we are free to execute our program.cs file in parallel.

Let's say we start a loop here. Once the loop is finished we can print another message that looping is finished now. We also print the message that program.cs is now waiting for MyFunction to send its return data.

Program.cs file now pauses its execution by using the await keyword on the task object. This task object was obtained in the beginning from cmc.MyFunction.

While program.cs file waits, let us come back to MyFunction!

Add a message that 5 seconds have expired, and the task is finished.

The return statement returns i. The compiler automatically wraps it in a Task.


// WATCH VIDEO FOR A BETTER EXPLANATION 

// program.cs file 


MyClass cmc = new();

Console.WriteLine("1. Program.cs: starting a 5 sec task in parallel...");

Task<int> task = cmc.MyFunction();

Console.WriteLine("3. Program.cs: back for other works...");

Console.WriteLine("4. Program.cs: starting some loop...");

int y = 0;

for(; y < 10; y++)
{
  Console.WriteLine($"\tin program.cs loop {y}");
}

Console.WriteLine("5. Program.cs: looping done in...");

Console.WriteLine("6. Program.cs: waiting on MyFunction for data...");

int data = await task;

Console.WriteLine("8. Program.cs: data received! adding to y now...");

int finalResult = y + data;

Console.WriteLine($"9. Program.cs: total = {finalResult}");

Let's now come back to the program.cs file.


// output display 

1. Program.cs: starting a 5 sec task in parallel...
2. TASK: task started ...
3. Program.cs: back for other works...
4. Program.cs: starting some loop...
        in program.cs loop 0
        in program.cs loop 1
        in program.cs loop 2
        in program.cs loop 3
        in program.cs loop 4
        in program.cs loop 5
        in program.cs loop 6
        in program.cs loop 7
        in program.cs loop 8
        in program.cs loop 9
5. Program.cs: looping done!
6. Program.cs: waiting on MyFunction for data...
7. TASK: task completed after 5s! returning data...
8. Program.cs: data received! adding to y now...
9. Program.cs: total = 20


We can now add the variable y calculated in program.cs file to the data obtained from a long running function. The console writeline prints the combined result.

This is what is the whole point of asynchronous programming. We calculated y and we also started a parallel calculation of data from a long running task. We made an optimal use of the CPU. The main thread was able to make calculations of y by running its own loop.

Run the Project

Run the project now. We verify that all the messages appear in the same order as we expected them to.

The source code has been attached to the downloads of this tutorial. We recommend that you examine it yourself and satisfy yourself about the order of various calls.


This Blog Post/Article "(C# Language) Asynchronous Task Programming" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.