C# Async Await and Tasks

C# Code Snippets Async Await
Share:

About

In this code snippet, we will take a look at async and await in C#.

The aysnc keyword enables a method to use the await keyword. These two keywords together enable us to execute code asynchronously. When called an async method will return a Task

Task can be thought of as a “unit of work”. You can take a method and “make it/put it” into a Task. This task can then be awaited at a later point in your code allowing you to execute other code in the meantime. You can also make multiple tasks and execute them in parallel and then wait for the results from them. I covered this in a post about the TPL(Task Parallel Library) here.

If you take a look at this post I made about threads you will see that if there is a time-consuming task it will block the execution of the main thread(unresponsive UI) until it is done executing. This can be solved by either creating a new thread for the task in question or using async/await to execute the code asynchronously without starting a new thread(all multithreaded/parallel code can technically be considered asynchronous too). 

Generally, a thread should be created to help with CPU bound operations while using asynchronous execution(without spawning a thread) should be used for I/O bound operations.

I/O bound: Operations that won’t benefit from parallel execution such as reading a file or making a network request. While using threads, in this case, will help resolve blocking it isn’t the easiest/most efficient way. Keep in mind that creating a thread takes time and memory. Also, threads require the CPU to make context switching(switch from one thread to another) which takes time to perform.

CPU bound: Operations that will benefit from parallel execution. For example, let’s say you have an array of 20 numbers and you want to add 1 to each number. You can make two threads. Both will loop through the array and add 1 to the index that they are currently on. But thread 1 starts at index 0 and loops to index 9 meanwhile thread 2 goes from index 10 to index 19

Here is an analogy for better understanding the difference between the two. Imagine you have a shopping list of items. You will have to drive to a few different stores to complete your shopping list.

async/await:

    1. First, we go to the store at 8 A.M to buy some fruit. We manage to buy most of the fruit except oranges because they run out. A new delivery of oranges will arrive at 9 A.M. Instead of waiting we head to the next store to buy ourselves some new shoes.
    2. When we arrive at the shoe shop at 8:30 a.m. we find out that the store doesn’t open until 9.30 a.m. so we drive to the third store.
    3. At the clothes shop, we buy some new clothes and then head back to the first store to see if the oranges have arrived. 
    4. We arrive at the first store at 9 o’clock and buy the oranges. Finally, we head back to the shoe shop. We buy some new shoes and then go home.

threads:

    • We get 2 other people to help us with our shopping. Everyone goes to a different store at the same time and doesn’t return 
    • home until they get all the required items from that store.  
Let’s have a look at the code below to see how to use async and await.

Code:

using System;
using System.Threading.Tasks;

namespace AsyncAwaitAndTasks
{
    class Program
    {
        static async Task Main(string[] args)
        {
            #region Await a task

            //Await the task without blocking the main thread.
            await doWork();

            //We can also start multiple tasks.
            Task task1 = doWork();
            Task task2 = doWork();
            Task task3 = getDataFromDB();

            //Do other stuff here while we wait for our tasks to be completed.
            Console.WriteLine("Doing other stuff.");

            //Wait for the completion of tasks.
            await task1;
            await task2;
            int result = await task3;

            //Continue with other code...
            Console.WriteLine("Tasks are done. Continue with other code.");

            //You can also call and await an async method in the same line.
            //But keep in mind that your code will not proceed from this line until a result is returned. 
            int result2 = await getDataFromDB();

            #endregion



            #region Await multiple tasks and get the returned values

            Task[] tasks = new Task[3];

            //Create tasks.
            tasks[0] = getDataFromDB();
            tasks[1] = getDataFromDB();
            tasks[2] = getDataFromDB();

            //Wait for all the tasks to finish.
            Task.WaitAll(tasks);

            //Get the data from the tasks.
            foreach (var item in tasks)
                Console.WriteLine(item.Result);

            #endregion

            Console.ReadLine();
        }


        static async Task doWork()
        {
            //Simulate waiting on some resource like a DB, file, http call response, ...
            await Task.Delay(2000);
        }

        //This async method also returns a result.
        static async Task getDataFromDB()
        {
            //Simulate waiting on some resource like a DB, file, http call response, ...
            await Task.Delay(2000);

            //Let's pretend like we get this from a database...
            int value = 10;

            return value;
        }
    }
}
The async/await keywords are “syntactic sugar” for a state machine that will get implemented when the code gets lowered (see images below). Here is a great and very lengthy write-up about how async/await really works under the hood. Or you can check out this video.

Resulting output:

Share:

Leave a Reply

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

The following GDPR rules must be read and accepted:
This form collects your name, email and content so that we can keep track of the comments placed on the website. For more info check our privacy policy where you will get more info on where, how and why we store your data.

Advertisment ad adsense adlogger