Structured concurrency model in Swift - Time & Space Complexity
We want to understand how the time it takes to run code changes when using Swift's structured concurrency model.
Specifically, we ask: how does adding more concurrent tasks affect the total work done?
Analyze the time complexity of the following Swift code using structured concurrency.
func fetchData(n: Int) async {
await withTaskGroup(of: Void.self) { group in
for i in 1...n {
group.addTask {
await process(i)
}
}
}
}
func process(_ value: Int) async {
// Simulate work
try? await Task.sleep(nanoseconds: 1_000_000)
}
This code runs n tasks concurrently, each doing some work asynchronously.
Look for repeated actions that affect time.
- Primary operation: launching and running n concurrent tasks.
- How many times: exactly n times, once per task.
As n grows, the number of tasks grows linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 tasks launched and processed |
| 100 | 100 tasks launched and processed |
| 1000 | 1000 tasks launched and processed |
Pattern observation: The total work grows directly with n, so doubling n doubles the work.
Time Complexity: O(n)
This means the total time grows in direct proportion to the number of tasks you run.
[X] Wrong: "Because tasks run concurrently, adding more tasks doesn't increase total time."
[OK] Correct: Even if tasks run at the same time, the system still needs to start and manage each task, so total work grows with the number of tasks.
Understanding how concurrency affects time helps you explain how programs scale and manage work efficiently.
What if we changed from launching all tasks concurrently to launching them one after another? How would the time complexity change?
Practice
Solution
Step 1: Understand structured concurrency concept
Structured concurrency groups related tasks so they run safely and finish before the program moves on.Step 2: Compare options with concept
Only To group tasks so they run safely and complete before continuing correctly describes grouping tasks to run safely and complete before continuing.Final Answer:
To group tasks so they run safely and complete before continuing -> Option AQuick Check:
Structured concurrency = safe grouped tasks [OK]
- Thinking tasks run forever without waiting
- Believing tasks only run on main thread
- Confusing structured concurrency with avoiding async/await
Solution
Step 1: Recall correct task group syntax
Swift uses withTaskGroup(of: Type.self) { group in ... } to create a task group.Step 2: Check options for exact syntax
Only withTaskGroup(of: Int.self) { group in ... } matches the correct syntax; others are invalid or made-up.Final Answer:
withTaskGroup(of: Int.self) { group in ... } -> Option AQuick Check:
Task group syntax = withTaskGroup(of:) [OK]
- Using TaskGroup without 'with'
- Trying taskGroup.run which doesn't exist
- Using asyncGroup which is not a Swift keyword
func fetchValues() async -> [Int] {
await withTaskGroup(of: Int.self) { group in
group.addTask { 3 }
group.addTask { 7 }
group.addTask { 2 }
var results = [Int]()
for await value in group {
results.append(value)
}
return results.sorted()
}
}
Task {
let values = await fetchValues()
print(values)
}Solution
Step 1: Understand task group execution
The tasks return 3, 7, and 2 asynchronously. The for-await loop collects them in any order.Step 2: Analyze the return statement
The results array is sorted before returning, so output is sorted ascending: [2, 3, 7].Final Answer:
[2, 3, 7] -> Option BQuick Check:
Sorted results = [2, 3, 7] [OK]
- Assuming tasks run in order added
- Forgetting the sorting step
- Thinking code causes compile error
func calculateSum() async -> Int {
await withTaskGroup(of: Int.self) { group in
group.addTask { 10 }
group.addTask { 20 }
var total = 0
for value in group {
total += value
}
return total
}
}Solution
Step 1: Check for correct async iteration
When iterating over a task group, 'for await' must be used to await each task's result.Step 2: Identify missing 'await'
The code uses 'for value in group' instead of 'for await value in group', causing a syntax error.Final Answer:
Missing 'await' before 'for' loop -> Option CQuick Check:
Async iteration requires 'for await' [OK]
- Using 'for' instead of 'for await' on task groups
- Thinking tasks can't be added inside withTaskGroup
- Misunderstanding return type requirements
Solution
Step 1: Understand concurrency for multiple async tasks
Structured concurrency uses task groups to run multiple async tasks concurrently and wait for all to finish.Step 2: Evaluate options for correct concurrency usage
Use withTaskGroup to add two tasks fetching data and posts, then await all and return combined tuple correctly uses withTaskGroup to add tasks, await their completion, and combine results safely.Final Answer:
Use withTaskGroup to add two tasks fetching data and posts, then await all and return combined tuple -> Option DQuick Check:
Task groups run and wait for multiple tasks [OK]
- Running tasks sequentially losing concurrency benefits
- Using DispatchQueue with sleep instead of structured concurrency
- Not waiting for tasks to finish before returning
Ready to prove it?
Pass the test and this pattern moves unknown
