C# introduced the async and await keywords as part of the .NET Framework 4.5 to simplify asynchronous programming. These keywords allow us to write asynchronous code, making it more readable, maintainable.

In this blog post, we’ll explore more about the async and await and their usage.

How to use async and await keywords in C#?

In C# , we can use async and await keywords to mark a method to behave asynchronously, which allows it to operate in the background while other main process runs as usual.

Below steps allows a method to operate asynchronously.

  • Include the async keyword in the method declaration. This suggests that there are asynchronous operations in the method.
  • Use the await keyword inside the method before the long running operation.
  • Task<TResult> as the return type if the method returns a value, where TResult is the value’s type.
  • Task as the return type if the method returns nothing.

How does async work in C#?

  • When we mark a method with the async modifier, we are telling the C# compiler that this method is asynchronous, and it contains one or more await expressions ion it
  • An async method typically returns Task, or void.
  • The await keyword is the signal for the compiler to step in and initiate the asynchronous behavior, It tells the C# program to pause the execution of the async method and return control to the caller until the awaited task completes.

Async Await in C# Example 

Let’s take a simple example to understand the usage of async and await in C#: Please copy attached dummy file Sample.txt in C:\Temp folder before executing this example.

In this example:

  • We define an async method ReadFileDataAsync that reads the content of a file asynchronously using an instance of StreamReader.
  • The ReadFileDataAsync method is called asynchronously by await in the Main method, which is marked as async.
  • The ReadFileDataAsync method reads the entire content of the file using reader.ReadToEndAsync() and prints the content of the file to the console.

It will generate below output upon successful execution.

Async_Await_File_Read_Sample_1
Async_Await_File_Read_Sample_1

If you look at the output, the control didn’t stop at the line string fileData = await ReadFileDataAsync(filePath); and the main thread keep on printing the output on the console and once it received the fileData then it printed that on the console.

This example demonstrates how to use async and await to perform file reading operations asynchronously, allowing the application to remain responsive while reading the file’s content.

Implementation of Async and Await in C#:

1) Asynchronous Parallel Execution:

In the above example, the Main method starts two tasks using Task.Run to print “Task 1” and “Task 2”. It then awaits the completion of both tasks using Task.WhenAll and prints “Parallel execution completed!” to the console.

2) Asynchronous Data Processing with Parallel.ForEach :

The output will be the processed data, where each number from the list is multiplied by 2. If an error occurs, the catch block will be triggered, and the error message will be displayed.

3) Chaining Asynchronous Tasks using Async and Await:

The output will be the result of multiplying the sum of 2 and 3 by 4. If an error occurs, the catch block will be triggered, and the error message will be displayed.

Key points of using async & await

  • Async Naming Convention: It’s a good practice to name asynchronous methods with an “async” suffix\Prefix to make their purpose clear (e.g., DownloadDataAsync or AsyncDownloadData).
  • Async Entry Points: In C# 7.1 and later, you can use async as an entry point modifier for the Main method in console applications.
  • Task Cancellation: Utilize CancellationToken to gracefully cancel async operations when needed, this prevents unnecessary processing.
  • Async Lambda Expressions: You can use async lambda expressions to create asynchronous delegates.
  • Use Asynchronous APIs: When working with libraries, use asynchronous versions of methods where available (e.g., ReadAsync instead of Read for file I/O).
  • Dispose Async Resources: In Async code, ensure that objects implementing IDisposable are properly disposed. Use the using statement or await using (C# 8.0 and later) with async disposable objects.
  • Async LINQ: In C# 9.0 and later, you can use async methods in LINQ queries, which makes easier to work with asynchronous data streams.

Conclusion:

Asynchronous programming using the async and await pattern in C# is a powerful technique to improve the responsiveness and efficiency of applications. By leveraging async and await, developers can write code that remains responsive, utilizes system resources efficiently, and delivers a better user experience.