Introduction
In modern C# development, writing responsive and high-performance applications is very important. Whether you are building web applications, APIs, or desktop software, handling long-running operations efficiently is critical. This is where async and await in C# come into play.
Async and await help you write asynchronous code in a simple and readable way. Instead of blocking the main thread, they allow your application to continue running while waiting for tasks like database calls, file operations, or API requests.
In this article, we will explain how to use async and await in C# in simple words, understand how they work internally, and explore best practices with real-world examples.
What is Asynchronous Programming in C#?
Asynchronous programming means executing tasks without blocking the main thread.
In simple words, your application can do other work while waiting for a task to complete.
Example Without Async
public void GetData()
{
var data = FetchDataFromServer(); // Blocks thread
Console.WriteLine(data);
}
Here, the application waits until the data is fetched.
Example With Async
public async Task GetDataAsync()
{
var data = await FetchDataFromServerAsync();
Console.WriteLine(data);
}
Now, the thread is not blocked while waiting.
What is async in C#?
The async keyword is used to define a method as asynchronous.
Key Points
It allows the use of await inside the method
It usually returns Task, Task, or void (for event handlers)
Example
public async Task<string> GetMessageAsync()
{
return "Hello Async";
}
What is await in C#?
The await keyword is used to pause the execution of an async method until the awaited task is complete.
Key Points
It works only inside async methods
It does not block the thread
It resumes execution after task completion
Example
public async Task ProcessAsync()
{
await Task.Delay(2000);
Console.WriteLine("Task completed");
}
How async and await Work Internally
Behind the scenes, async and await use Task-based asynchronous programming.
The method starts execution
When await is reached, control returns to the caller
The task runs in the background
Once completed, execution resumes
This improves performance and responsiveness.
Return Types in Async Methods
1. Task
Used when no value is returned.
public async Task DoWorkAsync()
{
await Task.Delay(1000);
}
2. Task
Used when a value is returned.
public async Task<int> GetNumberAsync()
{
await Task.Delay(1000);
return 10;
}
3. void (Avoid if Possible)
Used only for event handlers.
public async void Button_Click(object sender, EventArgs e)
{
await Task.Delay(1000);
}
Real-World Example: Calling an API
public async Task<string> GetApiDataAsync()
{
using (HttpClient client = new HttpClient())
{
var response = await client.GetAsync("https://api.example.com/data");
return await response.Content.ReadAsStringAsync();
}
}
This allows non-blocking API calls.
Benefits of Using Async and Await in C#
Improves application responsiveness
Better performance for I/O operations
Easy to write and read compared to callbacks
Efficient use of system resources
Common Mistakes to Avoid
1. Blocking Async Code
var result = GetDataAsync().Result; // Avoid
This can cause deadlocks.
2. Not Using Await
GetDataAsync(); // Missing await
Task may not complete as expected.
3. Overusing Async
Do not use async for CPU-bound tasks unnecessarily.
Async vs Parallel Programming
| Feature | Async/Await | Parallel Programming |
|---|
| Purpose | I/O-bound tasks | CPU-bound tasks |
| Thread Usage | Minimal threads | Multiple threads |
| Example | API calls, DB queries | Data processing |
When to Use Async and Await in C#
Use async and await when:
Best Practices for Async Programming
1. Use Async All the Way
Avoid mixing sync and async code.
2. Use ConfigureAwait(false) (Advanced)
Improves performance in library code.
3. Handle Exceptions Properly
try
{
await DoWorkAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
4. Avoid Async Void
Except for event handlers.
Real-World Scenario
In a web application:
Multiple users send requests
Async APIs handle requests without blocking threads
Server handles more users efficiently
Summary
Async and await in C# are powerful features that help developers write non-blocking, efficient, and scalable applications. They simplify asynchronous programming and improve application performance, especially for I/O-bound operations like API calls and database queries. By following best practices and avoiding common mistakes, you can fully utilize async and await to build modern, high-performance applications.