1️⃣ Async / Await Fundamentals
What async Does
- Enables use of
await
- Transforms method into a state machine
- Returns:
TaskTask<T>ValueTaskValueTask<T>
It does not:
- Create a new thread
- Make code parallel automatically
What await Does
- Awaits a
Task
- If task not complete:
- Method pauses
- Thread returns to ThreadPool
- When task completes:
- Continuation resumes
Key Principle
Async = non-blocking I/O
Not parallelism
Not multithreading by default
2️⃣ Task vs Thread
Thread
- OS-level execution unit
- Heavyweight
- Limited in number
- Managed by OS scheduler
Task
- Abstraction over asynchronous operation
- Represents a unit of work
- May or may not use a thread
- Runs on ThreadPool by default
Important:
Tasks are not threads.
3️⃣ ThreadPool
- Shared pool of worker threads
- Used by ASP.NET Core
- Reuses threads for efficiency
- Prevents constant thread creation/destruction
Thread Pool Starvation
Occurs when:
- All ThreadPool threads are blocked
- New requests cannot execute
Common Causes:
.Result
.Wait()
- Blocking I/O
- Excessive
Task.Run()
4️⃣ Blocking Async — Why .Result Is Dangerous
var result = DoSomethingAsync().Result;
Problems:
- Blocks thread
- Can cause deadlocks (in SynchronizationContext environments)
- Causes thread pool starvation
- Destroys scalability
Why Deadlock Happens (UI / Old ASP.NET)
- Async continuation tries to resume on captured context
.Resultblocks that context
- Both wait forever
ASP.NET Core:
- No SynchronizationContext
- Deadlock unlikely
- But still bad practice
5️⃣ Task.WhenAll
Behavior
await Task.WhenAll(task1, task2);
- Waits for ALL tasks
- If any fails:
- Returned task is Faulted
- First exception rethrown when awaited
- All exceptions stored in InnerExceptions
Important Notes
- Does NOT cancel other tasks automatically
- Tasks must support CancellationToken
Cooperative Cancellation Pattern
var cts = new CancellationTokenSource(); try { await Task.WhenAll(tasks); } catch { cts.Cancel(); throw; }
Cancellation must be observed by tasks.
6️⃣ ValueTask vs Task
Task
- Reference type
- Always allocates
- Simpler to use
ValueTask
- Struct
- Avoids allocation when completed synchronously
- Designed for high-performance scenarios
When to Use ValueTask
- Method frequently completes synchronously
- High-throughput code
- Performance-sensitive libraries
Do NOT use casually.
7️⃣ Forgetting to Await
DoSomethingAsync();
This creates fire-and-forget behavior.
Problems:
- Exceptions go unobserved
- No completion guarantee
- Race conditions
- Request may end before task finishes
Fire-and-Forget — When Acceptable?
Rarely.
Better alternatives:
- BackgroundService
- IHostedService
- Queue-based worker
- Hangfire
8️⃣ ConfigureAwait(false)
What It Does
Prevents capturing SynchronizationContext.
Useful in:
- Library code
- UI apps
- Legacy ASP.NET
Not necessary in:
- ASP.NET Core (no SynchronizationContext)
9️⃣ Task.Run()
What It Does
Schedules work on ThreadPool.
When to Use
- Short CPU-bound work
When NOT to Use
- Inside ASP.NET Core for I/O
- Database calls
- HTTP calls
ASP.NET Core already runs on ThreadPool.
🔟 Exception Behavior in Async
If async method throws:
- Exception stored inside Task
- Thrown when awaited
If not awaited:
- Unobserved exception
- May crash process later
1️⃣1️⃣ Concurrency vs Parallelism
Concurrency
- Handling multiple tasks
- Often I/O-bound
- Async/await
Parallelism
- Multiple threads
- CPU-bound
- Parallel.ForEach
- Task.Run
1️⃣2️⃣ Common Async Interview Traps
- Thinking async creates threads
- Blocking async with
.Result
- Using Task.Run for I/O
- Ignoring cancellation tokens
- Misusing ValueTask
- Forgetting to await
🎯 Interview-Ready Summary
Async in C#:
- Is about scalability, not threads
- Prevents thread blocking during I/O
- Improves throughput in web servers
- Requires careful handling of exceptions and cancellation
- Should avoid sync-over-async patterns