Async and Await in C#: Make Your Code Run Smoothly

Async and Await in C#: Make Your Code Run Smoothly

15 Oct 2024
Beginner
505 Views
19 min read
Learn with an interactive course and practical hands-on labs

Free C# Foundation Course: Learn C# In 21 Days

Async and Await in c#

Async and await in C# are keywords that allow your code to do operations independently. It means that your software can perform long-running tasks such as downloading files or reading from a database without stopping or becoming unresponsive. "Async" declares a method that will execute background work, and "Await" suspends that method until the job is performed, enabling other code to continue executing in the interim.

In the C# tutorial, you will get the chance to learn what is async and await in C#?, the example of async and await in c#how async and await work together, asynchronous methods in C#, real-world use-cases of async and await, advance concept of async and await, and many more.

What is  Asynchronous Programming in C#?

Asynchronous Programming in C# allows you to build powerful applications that allow you to run multiple tasks together without blocking the main thread. By using this, you can make your applications more responsive and attractive. You can use async and await keywords to handle long-running operations, such as I/O tasks, by pausing execution until completion without freezing the application. 

Read More:
C# Developer Roadmap
New features added to C# 5.0
Introduction to C Sharp

What is async and await in C#?

Async and await in C# are keywords that enable asynchronous programming, which allows actions to be performed in the background without interfering with the main thread.

  • Async is used to indicate that a method is asynchronous, which means that it may do tasks without causing the application to halt.

What is async and await in C#

  • Await is used within an async method to pause execution while a job is performed, but it does not halt the rest of the program.

What is async and await in C#

Clear your mind, and let's focus on this example:

Example

 using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Fetching data...");        
        // Call the asynchronous method
        string result = await FetchDataAsync();
        Console.WriteLine(result);
    }
    // Asynchronous method that simulates a long-running task
    public static async Task<string> FetchDataAsync()
    {
        // Simulate a delay (e.g., waiting for data from an API)
        await Task.Delay(3000); // Wait for 3 seconds        
        return "Data fetched successfully!";
    }
}    

Output

 Fetching data...
Data fetched successfully!

Explanation

In this example,

  • We declared the Main function as async and used the FetchDataAsync() method with await. It waits for the outcome without interrupting the application.
  • The FetchDataAsync function is also designated async and mimics a three-second delay using Task.Delay(3000). During the wait, the software might continue to do other activities.
  • After 3 seconds, the procedure returns "Data fetched successfully!" which the main application outputs.

How Async and Await Work Together

In C#, async and await operate together to handle asynchronous activities efficiently. This keeps the program responsive and prevents it from blocking the main thread during long-running processes.

  • Async method declaration: When you declare a method with the async keyword, it indicates that it will perform asynchronous actions.
  • Await keyword: In this async method, you use the await keyword before calling an asynchronous operation. This is where the magic happens: instead of blocking the whole function while waiting for the job to finish, await pauses the method's execution until the task is completed. Meanwhile, the remainder of the program can continue to execute other code.
  • Task continuation: When the machine completes the asynchronous task, the function returns to the place where it was paused by await and begins execution.

The step-by-step flow of Async and Await in C#

  • Step 1: A method is marked with async and starts executing.
  • Step 2: When an asynchronous operation (like a network call) is encountered, you use await.
  • Step 3: The method execution is paused at the await line, and the program is free to continue running other tasks.
  • Step 4: Once the awaited task is completed, the method picks up where it left off and continues.

Example

 using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Starting data fetch...");
        // Call the asynchronous method and await its result
        string result = await GetDataAsync();
        // Print the result after the async operation completes
        Console.WriteLine(result);
    }

    // Asynchronous method to simulate fetching data with a random delay
    public static async Task<string> GetDataAsync()
    {
        // Generate a random delay between 1 and 5 seconds
        Random random = new Random();
        int delay = random.Next(1000, 5000); // Random delay between 1000ms and 5000ms
        // Simulate an asynchronous operation with the random delay
        await Task.Delay(delay);
        // Code resumes here after the delay
        return $"Data has been fetched after {delay / 1000} seconds!";
    }
}    

Output

 Starting data fetch...
Data has been fetched after 3 seconds!

Explanation

In this example,

  • The program simulates fetching data with a random delay between 1 and 5 seconds, mimicking a server response time.
  • It uses async and await to perform the delay without freezing the application, allowing other tasks to run simultaneously.
  • After the delay, it prints a message indicating how long it took to "fetch" the data, enhancing user experience by keeping the app responsive.

Asynchronous Methods in C#

Asynchronous methods let a program do multiple things at once so it can keep running while waiting for tasks that take a long time to finish, like downloading a file or fetching data from the internet. This makes the app more responsive and user-friendly, allowing users to keep interacting with it without delays.

Key Features of the Asynchronous Method

  • Async: To define an asynchronous method, include the async keyword in the method definition. This implies that the procedure uses asynchronous operations.
  • Return types: Asynchronous methods usually return Task, Task<T>, or void (the latter is intended for event handlers). Task is used for methods that do not return a value, whereas Task<T> is for those that do return a result.
  • Using await: In an asynchronous method, use the await keyword to suspend execution until the awaited job is completed. This permits other code to execute while the job is being completed.

Example

 using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Starting operation...");
        
        // Call the asynchronous method
        string result = await PerformTaskAsync();
        
        Console.WriteLine(result);
    }

    // Asynchronous method
    public static async Task<string> PerformTaskAsync()
    {
        // Simulate a long-running operation
        await Task.Delay(3000); // Wait for 3 seconds

        return "Operation completed successfully!";
    }
}    

Output

 Starting operation...
Operation completed successfully!

Explanation

In this example

  • PerformTaskAsync is an asynchronous function that copies a delay (such as fetching data) with Task.Delay.
  • Using the await keyword, the Main method may wait for PerformTaskAsync to finish without stopping the main thread.
Read More:
Difference between c sharp generics and Collections with example
Top 20 C# Features Every .NET Developer Must Know in 2024
Mastering OOPs Concepts in C#: A Comprehensive Guide
Understanding Type Casting or Type Conversion in C#

Real-world Use Cases of Async and Await in C#

  • Using in Web API Calls: Fetching data from web services without blocking the user interface, allowing users to continue interacting with the app while data is loading.
  • Using in File I/O Operations: Reading or writing files asynchronously, enabling other tasks to run while waiting for file access, which enhances performance in file-heavy applications.
  • Database Queries: Executing database queries in the background, preventing the application from freezing during data retrieval, especially with large datasets.
  • User Interface (UI) Updates: Keeping the UI responsive during long-running tasks (like image processing or data analysis) by performing those tasks asynchronously.
  • Handling Stream Data: Handling real-time data streams, such as video or audio processing, where tasks can be performed in the background without interrupting playback.
  • Executing Batch Processing: Executing multiple tasks in parallel, such as sending multiple emails or processing multiple transactions, to improve overall efficiency.

Advanced Concepts in Async and Await in C#

There are several advanced key concepts in Async and Await in C# that are:

1. Task Cancellation with async and await

  • Use CancellationToken to gracefully cancel ongoing asynchronous operations.
  • Combine Task.Run() with a CancellationToken to manage the cancellation flow and avoid resource leaks.

2. Handling Exceptions in Asynchronous Code

  • Exceptions thrown in asynchronous methods are captured in the returned Task and can be accessed using .Wait() or .Result().
  • Use try-catch inside an async method to handle exceptions, or check Task.Exception for unhandled exceptions in non-awaited tasks.

3. Deadlock Scenarios with async and await

  • Avoid blocking the main thread by calling .Result or .Wait() on an asynchronous method, especially in a UI context, as it can lead to deadlocks.
  • Use ConfigureAwait(false) to prevent deadlocks in library code where synchronization with the original context is not required.

4. Concurrency with async and await

  • Use Task.WhenAll() to run multiple asynchronous tasks concurrently and wait for all of them to complete.
  • Use Task.WhenAny() to handle the first completed task in a set of tasks, improving responsiveness.

5. Avoiding async void Pitfalls

  • Avoid using async void in most cases except for event handlers, as it doesn’t allow the caller to handle exceptions or await the method's completion.
  • Prefer returning Task in async methods to ensure proper exception handling and task continuation.

Difference Between Async and Await in C#

Let's go through the basic difference between Async and Await in C#

FactorsAsyncAwait
PurposeDeclares a method as asynchronousPauses execution until the awaited task is completed.
UsageUsed in the method signature (e.g., public async Task<string> MyMethod())Used within the method body before calling a task (e.g., await SomeAsyncMethod())
BehaviorAllows the method to contain await expressions; can return Task, Task<T>, or voidThis causes the method to yield control back to the caller until the awaited task finishes
Execution FlowBegins execution when called, may not complete immediately if there are await callsYields control back to the caller when encountered, resuming when the awaited task is done
Error HandlingErrors can be caught using standard try-catch blocksExceptions from awaited tasks can be handled in the calling method's try-catch block

Advantages of Async and Await in C#

  • Improved Responsiveness: Keeps applications responsive by allowing them to continue processing other tasks while waiting for long-running operations to complete.
  • Simplified Code: Makes asynchronous code easier to read and write, reducing complexity compared to traditional callback methods.
  • Efficient Resource Utilization: Optimizes resource usage by freeing up threads while waiting for I/O operations, leading to better performance.
  • Error Handling: Simplifies error handling in asynchronous operations using try-catch blocks, making it easier to manage exceptions.
  • Scalability: Enhances scalability in applications, especially web applications, by efficiently handling many simultaneous operations without blocking threads.

Disadvantages of Async and Await in C#

  • Complexity: While it simplifies some scenarios, it can introduce complexity in debugging and understanding the flow of asynchronous code, especially with multiple await calls.
  • Overhead: The state machine generated by the compiler for async methods can introduce some performance overhead, making them slightly slower than synchronous methods in certain scenarios.
  • Error Handling: Mismanagement of exceptions can lead to unhandled exceptions if not properly awaited or if async void methods are used.
  • Context Switching: Frequent context switching between threads can impact performance in high-load scenarios, especially if not managed properly.
  • Increased Memory Usage: Async methods may use more memory due to the state machine and potential continuation objects, particularly in long-running or heavily asynchronous applications.
Read More:
OOPs Interview Questions and Answers in C#
Top 50 C# Interview Questions and Answers To Get Hired
Conclusion

In conclusion, we have covered the advanced concepts of async and await in C#, including task cancellation, handling exceptions, concurrency, and asynchronous streams. These techniques enhance the performance and responsiveness of applications by enabling non-blocking asynchronous programming. For mastering .Net technology, ScholorHat comes up with a Full-Stack .NET Developer Certification Training Course and .NET Solution Architect Certification Training, which will help you in your career growth.

FAQs

async and await enable non-blocking I/O operations. Instead of waiting for tasks like file operations or web requests to finish, they allow other code to run, improving responsiveness and resource utilization. 

Not every method should be marked as async. A method can only be marked async if it contains at least one await expression that returns a Task, Task<T>, or IAsyncEnumerable<T>

Yes, but it’s not recommended. Without await, the method will execute synchronously and return a Task. You’ll miss out on the key benefits of asynchronous programming, such as freeing up threads for other tasks. 

Task represents an asynchronous operation that doesn’t return a value, while Task<T> represents an asynchronous operation that returns a result of type T. Use Task<T> when you need a result from the async method. 

Take our Csharp skill challenge to evaluate yourself!

In less than 5 minutes, with our skill challenge, you can identify your knowledge gaps and strengths in a given skill.

GET FREE CHALLENGE

Share Article
About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan, Founder and CEO of ScholarHat by DotNetTricks, is a renowned expert in System Design, Software Architecture, Azure Cloud, .NET, Angular, React, Node.js, Microservices, DevOps, and Cross-Platform Mobile App Development. His skill set extends into emerging fields like Data Science, Python, Azure AI/ML, and Generative AI, making him a well-rounded expert who bridges traditional development frameworks with cutting-edge advancements. Recognized as a Microsoft Most Valuable Professional (MVP) for an impressive 9 consecutive years (2016–2024), he has consistently demonstrated excellence in delivering impactful solutions and inspiring learners.

Shailendra’s unique, hands-on training programs and bestselling books have empowered thousands of professionals to excel in their careers and crack tough interviews. A visionary leader, he continues to revolutionize technology education with his innovative approach.
Accept cookies & close this