C sharp - Asynchronous Programming in C# (async / await – In Depth)
Asynchronous programming allows a program to execute long-running operations without blocking the main thread.
It improves:
-
Responsiveness (UI apps)
-
Scalability (web apps)
-
Resource efficiency
1. Synchronous vs Asynchronous
Synchronous (Blocking)
public string GetData()
{
Thread.Sleep(5000);
return "Data Loaded";
}
Here:
-
The thread is blocked for 5 seconds.
-
Nothing else runs during this time.
Problem:
-
UI freezes
-
Web server thread is occupied
Asynchronous (Non-Blocking)
public async Task<string> GetDataAsync()
{
await Task.Delay(5000);
return "Data Loaded";
}
Here:
-
The thread is released while waiting.
-
Other work can execute.
2. Core Keywords
async
Marks a method as asynchronous.
await
Suspends execution until the awaited task completes.
Important:
-
awaitonly works inside anasyncmethod. -
It does NOT create a new thread automatically.
-
It enables non-blocking continuation.
3. Task and Task
C# uses Task to represent asynchronous operations.
| Type | Meaning |
|---|---|
| Task | No return value |
| Task | Returns value of type T |
Example:
public async Task<int> AddAsync(int a, int b)
{
await Task.Delay(1000);
return a + b;
}
4. How async/await Actually Works
When the compiler sees:
await SomeTask();
It:
-
Splits method into state machine
-
Returns control to caller
-
Resumes execution after task completes
This is called:
State Machine Transformation
The compiler generates hidden code to manage continuation.
5. CPU-bound vs I/O-bound Operations
I/O-bound (Best for async)
-
Database calls
-
API calls
-
File operations
-
Network requests
Example:
await httpClient.GetAsync(url);
CPU-bound (Use Task.Run)
If heavy computation:
await Task.Run(() => HeavyCalculation());
Why?
Because CPU work still blocks thread unless moved to background.
6. Avoiding Common Mistakes
Mistake 1: Using .Result or .Wait()
var result = GetDataAsync().Result;
This can cause:
-
Deadlocks
-
Thread blocking
Always use await.
Mistake 2: async void (Except Event Handlers)
Bad:
async void MyMethod()
Use:
async Task MyMethod()
Reason:
-
async void cannot be awaited
-
Exceptions cannot be caught properly
Exception:
-
Event handlers must be async void
7. Exception Handling in Async
try
{
await GetDataAsync();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Important:
-
Exceptions are stored inside Task
-
They are thrown when awaited
8. Parallel Execution
To run tasks simultaneously:
Task t1 = Task.Delay(2000);
Task t2 = Task.Delay(3000);
await Task.WhenAll(t1, t2);
Task.WhenAll waits for all tasks.
Task.WhenAny waits for first completed.
9. Synchronization Context
In UI apps:
-
After await, execution resumes on original UI thread.
In ASP.NET Core:
-
No synchronization context.
-
Continuation runs on thread pool.
This affects performance and deadlock behavior.
10. Real-World Example (API Call)
public async Task<string> GetApiData()
{
using HttpClient client = new HttpClient();
var response = await client.GetStringAsync("https://example.com");
return response;
}
Benefits:
-
Thread not blocked
-
Server handles more requests
-
UI remains responsive
11. Performance Benefits
Without async:
-
1000 requests = 1000 blocked threads
With async:
-
Threads reused
-
Higher scalability
-
Lower memory usage
That is why ASP.NET Core heavily uses async.