Async sequences (AsyncSequence) in Swift - Time & Space Complexity
When working with async sequences, it's important to understand how the time to process elements grows as the sequence gets longer.
We want to know how the number of steps changes when we read more items asynchronously.
Analyze the time complexity of the following code snippet.
func printNumbers(n: Int) async {
for await number in AsyncStream { cont in
for i in 1...n {
cont.yield(i)
}
cont.finish()
} {
print(number)
}
}
This code asynchronously prints numbers from 1 to n using an async sequence.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The asynchronous loop that waits for and processes each number in the sequence.
- How many times: It runs once for each number from 1 to n, so n times.
As the number of items n increases, the total steps increase roughly in direct proportion.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 async steps |
| 100 | About 100 async steps |
| 1000 | About 1000 async steps |
Pattern observation: The time grows steadily as you add more items, roughly one step per item.
Time Complexity: O(n)
This means the time to process the async sequence grows linearly with the number of items.
[X] Wrong: "Async sequences run all items at once, so time doesn't grow with n."
[OK] Correct: Async sequences produce items one by one, so processing time adds up with each item.
Understanding async sequences' time behavior shows you can reason about asynchronous code performance, a key skill in modern Swift development.
"What if we changed the async sequence to produce items in parallel? How would the time complexity change?"