async & await in C#

"async" and "await" are language level constructs in C# used for asynchronous programming. Keywords "async" and "await" and types Task and Task<T> together constitute the task based async model in .NET.
Asynchronous programming is different from multi-threading. In multi-threading separate threads are created to do some background job, while in asynchronous programming tasks are executed asynchronously mainly on the current thread but you can make a task to run on a separate thread using Task.Run method (usually done for CPU bound job).

Task represent some work that is to be done and as mentioned above a task can either be run asynchronously on the same thread using just await without Task.Run or on a separate thread using Task.Run. Each of these methods are used in different scenario as illustrated below:-

  1. Running asynchronously on same thread :-

    When we are doing some I/O bound work like extracting data from database, calling a web service etc. in such scenario use await on the I/O bound operation without Task.Run inside an async method.
    private async Task ReadDataFromDBAsync()
    {
        // Reads some string from DB and returns it
    }
    
    public async void GetDataAsync()
    {
        // At this line the control is yielded to the calling method
        string stringData = await ReadDataFromDBAsync();
        Console.WriteLine(stringData);
    }
    
  2. Running on separate thread using Task.Run :-

    When we are doing some work that includes high computation (i.e. doing some CPU bound work) then we use await on the operation started on a separate background thread Using Task.Run method.
    private string Calculate()
    {
        // Does some high computation task
    }
    
    
    public async void ExecuteAsync()
    {
        // Here the control is yielded to the calling method while the CPU bound job is done on a separate thread
        var result = await Task.Run(() => Calculate());
        Console.WriteLine(result);
    };


Lets take a look at each of these terms that we used:-

  • async - The async keyword enables us to use await inside a method. In other words it makes a method an async method.
  • await - The await keyword is the backbone of .NET async model. It suspends the current method and yields control back to the calling method. After the awaited task is complete the remaining code (after await) in the async method is executed. Thus await allows the application to be functional while a task is waiting to complete its execution.
  • Task & Task<T> - A Task represent an operation while Task<T> represent an operation that return a value. The await keyword allows a Task to run asynchronously by yielding control to its caller until the task is complete.In case of Task<T> the await also unwraps the value returned by it.


Difference in normal execution and asynchronous execution:-

  1. Normal execution
    public void ProcessData()
    {
     ReadData();
     Console.WriteLine("After calling ReadData"); 
    }
    
    public void ReadData()
    {
     var stringData = _httpClient.GetStringAsync("https://www.google.com").Result;
     Console.WriteLine("After completing GetStringAsync");
    }
    

    The output of above code on calling ProcessData() is:
    After completing GetStringAsync
    After calling ReadData

  2. Asynchronous execution
    public void ProcessData()
    {
     ReadDataAsync();
     Console.WriteLine("After calling ReadData"); 
    }
    
    public async void ReadDataAsync()
    {
     var stringData = await _httpClient.GetStringAsync("https://www.google.com");
     Console.WriteLine("After completing GetStringAsync");
    }
    

    The output of above code on calling ProcessData() is:
    After calling ReadData
    After completing GetStringAsync
NOTE : It is not a good practice to use async void, avoid using it in the actual code except for the event handlers.

No comments:

Post a Comment