Swift Tutorial · Swift Concurrency · Lesson 23 of 30
Swift Task Groups and Cancellation
Run a dynamic number of child tasks with task groups, collect their results, and handle cancellation.
Task groups
withTaskGroup runs any number of child tasks concurrently. Results arrive in completion order, so sort or
key them if order matters. The group waits for all children before returning (structured concurrency).
func price(of sku: String) async -> Double {
try? await Task.sleep(for: .milliseconds(Int.random(in: 10...50)))
return Double(sku.count) * 2.5
}
let skus = ["mug", "teapot", "kettle", "spoon"]
let prices = await withTaskGroup(of: (String, Double).self) { group in
for sku in skus {
group.addTask { (sku, await price(of: sku)) }
}
var result: [String: Double] = [:]
for await (sku, price) in group { result[sku] = price }
return result
}
for sku in skus { print(sku, prices[sku]!) }
print("total", prices.values.reduce(0, +))
Output
mug 7.5 teapot 15.0 kettle 15.0 spoon 12.5 total 50.0
Run this on your computer — see “Get Started” for setup.
Cancellation
Cancellation is cooperative: a cancelled task keeps running until it checks Task.isCancelled or calls
try Task.checkCancellation(). Task.sleep throws CancellationError when its task is cancelled.
let task = Task {
var processed = 0
for _ in 1...100 {
do {
try await Task.sleep(for: .milliseconds(20))
} catch {
return "cancelled after \(processed) items"
}
processed += 1
}
return "finished all items"
}
try? await Task.sleep(for: .milliseconds(110))
task.cancel()
let outcome = await task.value
print(outcome.hasPrefix("cancelled") ? "the task stopped early" : outcome)
Output
the task stopped early
Run this on your computer — see “Get Started” for setup.
Test yourself
In what order does a task group deliver results?
In the order they were addedIn the order the child tasks finishAlphabeticallyRandomly, but always the same
Show answer
Answer: In the order the child tasks finish