Task groups for parallel execution in Swift - Time & Space Complexity
When using task groups for parallel execution, we want to know how the total work grows as we add more tasks.
We ask: How does running many tasks at once affect the time it takes?
Analyze the time complexity of the following code snippet.
func fetchAllData(n: Int) async {
await withTaskGroup(of: String.self) { group in
for i in 1...n {
group.addTask {
await fetchData(id: i)
}
}
for await result in group {
print(result)
}
}
}
func fetchData(id: Int) async -> String {
// Simulate network call
return "Data \(id)"
}
This code runs n tasks in parallel to fetch data, then waits for all to finish.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding and running n tasks in the task group.
- How many times: The loop runs n times, creating n parallel tasks.
As n grows, the number of tasks grows linearly, but tasks run at the same time.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 tasks run in parallel |
| 100 | 100 tasks run in parallel |
| 1000 | 1000 tasks run in parallel |
Pattern observation: The number of tasks grows with n, but total time depends on the longest single task, not the sum.
Time Complexity: O(T)
This means the total time to complete all tasks stays roughly the same as n grows, assuming tasks run truly in parallel and each task takes time T.
[X] Wrong: "More tasks always mean more total time because they add up."
[OK] Correct: When tasks run in parallel, total time depends on the slowest task, not the number of tasks.
Understanding how parallel tasks affect time helps you explain real-world app performance and shows you can think about efficient code.
"What if tasks run sequentially instead of in parallel? How would the time complexity change?"
Practice
TaskGroup in Swift concurrency?Solution
Step 1: Understand what TaskGroup does
A TaskGroup lets you run many tasks at the same time, managing them together.Step 2: Identify the main use
It allows parallel execution and waits until all tasks finish before continuing.Final Answer:
To run multiple tasks in parallel and wait for all to complete -> Option AQuick Check:
TaskGroup = parallel tasks + wait [OK]
- Thinking TaskGroup runs only one task
- Confusing TaskGroup with error handling
- Assuming TaskGroup pauses tasks
TaskGroup in Swift?Solution
Step 1: Recall the method to add tasks
The correct method to add a task isaddTaskwith a closure.Step 2: Check syntax correctness
group.addTask { await fetchData() } usesgroup.addTask { await fetchData() }, which is the right syntax.Final Answer:
group.addTask { await fetchData() } -> Option CQuick Check:
Use addTask with closure [OK]
- Using wrong method names like runTask or createTask
- Not using closure syntax
- Omitting await inside the task
func fetchNumber(_ n: Int) async -> Int {
return n * 2
}
func runGroup() async {
await withTaskGroup(of: Int.self) { group in
for i in 1...3 {
group.addTask { await fetchNumber(i) }
}
var results = [Int]()
for await result in group {
results.append(result)
}
print(results.sorted())
}
}
Task {
await runGroup()
}Solution
Step 1: Understand the task group adds tasks for numbers 1 to 3
Each task returns the input number multiplied by 2: 2, 4, and 6.Step 2: Collect results and sort them before printing
Results are collected in any order but sorted before printing, so output is [2, 4, 6].Final Answer:
[2, 4, 6] -> Option DQuick Check:
Results doubled and sorted = [2,4,6] [OK]
- Assuming results print in order added
- Forgetting to await inside addTask
- Confusing output with original numbers
await withTaskGroup(of: Int.self) { group in
for i in 1...3 {
group.addTask { fetchNumber(i) }
}
for await result in group {
print(result)
}
}
Assuming fetchNumber is an async function.Solution
Step 1: Check how fetchNumber is called inside addTask
fetchNumber is async, so it must be awaited inside the closure.Step 2: Identify missing await keyword
The closure callsfetchNumber(i)withoutawait, causing a compile error.Final Answer:
Missing await inside addTask closure -> Option AQuick Check:
Async calls inside addTask need await [OK]
- Forgetting await inside addTask
- Thinking for await can't be used with TaskGroup
- Declaring TaskGroup incorrectly
Solution
Step 1: Understand the goal to run tasks in parallel and filter nil
Running tasks in parallel with TaskGroup allows concurrency; filtering nil after collecting results is straightforward.Step 2: Evaluate options for filtering nil results
Add tasks returning optional data, then filter non-nil in for await loop correctly adds tasks returning optional data and filters non-nil results in the for await loop, matching the goal.Final Answer:
Add tasks returning optional data, then filter non-nil in for await loop -> Option BQuick Check:
Filter nil after parallel tasks with for await [OK]
- Trying to run tasks sequentially losing parallelism
- Ignoring errors without filtering nil
- Misusing throwing task groups for simple filtering
Ready to prove it?
Pass the test and this pattern moves unknown
