Async/Await — The City's Parallel Construction
20 XPHard
Ctrl+Enter RunCtrl+S Save
⚡ Asynchronous Programming in C#
Imagine our .NET city is booming — dozens of buildings need to go up simultaneously. If we built them one at a time (synchronously), it would take forever. Instead, the city hires multiple crews that work in parallel, reporting back when each building is done.
That's exactly what async/await gives you: the ability to start long-running operations without blocking the main thread, then resume when results are ready.
🔑 Core Concepts
Task — represents an asynchronous operation that may or may not return a value.
Task<T> — represents an async operation that returns a value of type T.
async keyword — marks a method as asynchronous, allowing it to use await.
await keyword — suspends execution until the awaited Task completes, without blocking the thread.
// A simple async method
async Task<string> BuildFloorAsync(string building, int floor)
{
await Task.Delay(100); // Simulate construction time
return $"{building}: Floor {floor} done";
}
// Calling it
string result = await BuildFloorAsync("Tower A", 3);
🏗️ Task.Delay — Simulating Work
Task.Delay(ms) is the async equivalent of Thread.Sleep, but it does not block the thread. The thread is free to do other work while the delay elapses.
// BAD — blocks the thread
Thread.Sleep(2000);
// GOOD — releases the thread
await Task.Delay(2000);
🚀 Task.WhenAll — Parallel Execution
Task.WhenAll takes multiple tasks and returns a single Task that completes when all of them finish. This is how we build multiple buildings at once.
Task buildA = BuildAsync("A", 3);
Task buildB = BuildAsync("B", 5);
// Both run concurrently — total time ≈ max(timeA, timeB)
await Task.WhenAll(buildA, buildB);
Console.WriteLine("All buildings done!");
🏎️ Task.WhenAny — First to Finish
Task.WhenAny completes as soon as any one of the tasks finishes — useful for timeouts or racing multiple data sources.
Task<string> fast = FetchFromCacheAsync();
Task<string> slow = FetchFromDatabaseAsync();
Task<string> winner = await Task.WhenAny(fast, slow);
string data = await winner; // Get the result of whichever finished first
💡 Why Async Matters
Non-blocking I/O — File reads, HTTP calls, and DB queries don't freeze your app.
Responsive UIs — Desktop/mobile apps stay interactive during long operations.
Scalable servers — ASP.NET can handle thousands of concurrent requests because threads aren't wasted waiting.
Resource efficiency — Fewer threads needed, less memory consumed.
⚠️ Common Pitfalls
async void — Only use for event handlers. Exceptions in async void methods crash the process.
Blocking on async code — Never call .Result or .Wait() on a Task in a synchronous context — it can deadlock.
Forgetting await — If you don't await a Task, exceptions are silently swallowed and the operation may not complete before your method returns.
📋 Instructions
**The City's Parallel Construction**
Build a program that constructs two buildings asynchronously:
1. Create an `async Task BuildAsync(string name, int floors)` method that:
- Prints `"{name}: Started"`
- Awaits `Task.Delay(100)` to simulate construction
- Prints `"{name}: Complete! ({floors} floors)"`
2. In `Main`:
- Print `"Starting construction..."`
- Start **both** `BuildAsync("Building A", 3)` and `BuildAsync("Building B", 5)` tasks
- Use `Task.WhenAll` to await both
- Print `"All buildings done!"`
Define an async method `BuildAsync` that prints start, awaits Task.Delay(100), then prints complete. In Main, store both calls as Task variables (don't await them individually yet), then use `await Task.WhenAll(task1, task2)` to run them concurrently.