Async and await keywords in C Sharp (C#) - Time & Space Complexity
When using async and await, we want to understand how the program's work changes as input grows.
We ask: How does waiting for tasks affect the total time spent?
Analyze the time complexity of the following code snippet.
async Task ProcessItemsAsync(List<int> items)
{
foreach (var item in items)
{
await Task.Delay(100); // Simulate async work
}
}
This code processes each item in a list, waiting asynchronously for 100 milliseconds per item.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The foreach loop runs once per item.
- How many times: Exactly as many times as there are items in the list.
Each item adds a fixed wait time, so total time grows directly with the number of items.
| Input Size (n) | Approx. Operations (waits) |
|---|---|
| 10 | 10 waits of 100ms each |
| 100 | 100 waits of 100ms each |
| 1000 | 1000 waits of 100ms each |
Pattern observation: Total time increases linearly as the list grows.
Time Complexity: O(n)
This means the total time grows in direct proportion to the number of items processed.
[X] Wrong: "Using async and await makes the code run instantly or in constant time."
[OK] Correct: Async lets the program wait without blocking, but the total work still depends on how many items you process.
Understanding how async code scales helps you write efficient programs and explain your reasoning clearly in interviews.
"What if we started all the tasks at once and awaited them together? How would the time complexity change?"
Practice
async keyword in C#?Solution
Step 1: Understand the role of
Theasyncasynckeyword marks a method so it can run asynchronously, allowing other work to continue without waiting.Step 2: Differentiate from other options
It does not automatically make code faster or use multiple threads, nor does it pause execution by itself.Final Answer:
To mark a method that can run asynchronously without blocking the caller -> Option BQuick Check:
async marks asynchronous methods = A [OK]
- Thinking async makes code multithreaded automatically
- Confusing async with pausing execution
- Believing async only works with void methods
Solution
Step 1: Recall async method return types
Async methods that return a value must returnTask<T>, whereTis the return type, herestring.Step 2: Check syntax correctness
public async Task<string> GetData() correctly usesasync Task<string>. Other options have wrong order or missingTask.Final Answer:
public async Task<string> GetData() -> Option DQuick Check:
Async methods returning values use Task<T> = A [OK]
- Placing async after return type
- Returning just string instead of Task<string>
- Using async keyword incorrectly in method signature
async Task<int> GetNumberAsync() { await Task.Delay(100); return 5; }
async Task Main() { var result = await GetNumberAsync(); Console.WriteLine(result); }Solution
Step 1: Understand async method behavior
The methodGetNumberAsyncwaits 100ms then returns 5 asynchronously.Step 2: Await the result and print
TheMainmethod awaitsGetNumberAsyncand prints the returned value, which is 5.Final Answer:
5 -> Option AQuick Check:
Await returns method result = 5 [OK]
- Expecting Task object printed instead of value
- Ignoring await causing wrong output
- Thinking async delays block main thread
async Task<int> CalculateAsync() { return 10; }
void Main() { var result = CalculateAsync(); Console.WriteLine(result); }Solution
Step 1: Analyze method call and return type
CalculateAsyncreturns aTask<int>, butMaincalls it withoutawait, soresultis a Task, not int.Step 2: Understand how to get actual value
To get the int value,awaitmust be used, butMainis not async, so this is a problem.Final Answer:
Missing await keyword when calling CalculateAsync -> Option AQuick Check:
Call async method with await = C [OK]
- Calling async method without await
- Expecting async method to return direct value
- Making Main async without proper signature
Solution
Step 1: Understand running tasks concurrently
Starting both tasks without awaiting immediately lets them run in parallel.Step 2: Await both tasks after starting
Awaiting each task after starting both ensures you wait for both to finish and get results efficiently.Step 3: Analyze other options
var result1 = await Task1(); var result2 = await Task2(); awaits sequentially, running tasks one after another. var result1 = Task1().Result; var result2 = Task2().Result; blocks synchronously causing deadlocks. await Task.WhenAll(Task1(), Task2()); var result1 = Task1().Result; var result2 = Task2().Result; awaits but then calls Result again, causing redundant calls.Final Answer:
var task1 = Task1(); var task2 = Task2(); var result1 = await task1; var result2 = await task2; -> Option CQuick Check:
Start tasks first, then await both = B [OK]
- Awaiting tasks one by one causing sequential execution
- Using .Result causing blocking and deadlocks
- Calling tasks multiple times causing duplicate work
Ready to prove it?
Pass the test and this pattern moves unknown
