TaskGroup - Concurrent requests similar to DispatchGroup
- withTaskGroup - No throw variant. grp conforms to AsyncSequence, so return value could be collated by
for await
loop orwhile let item = await grp.next()
orawait grp.reduce(initial, transform)
..waitForAll()
will discard the result though. -- returnValue for each Task within the group should be the same representingawait withTaskGroup(String.self)
but overall group could return a different data type as well with collated Task results.
let something = await withTaskGroup(String.self) { grp -> String
grp.addTask {
...
...
return "abc"
}
grp.addTask {
...
...
return "def"
}
var collectedReturn = ""
//3 Ways to fetch
for await val in grp {
// indv return from indv task and collate
collectedReturn += val
}
return collectedReturn }
//OR
return await grp.reduce(""){$0 += $1} }
//OR
while let val = await grp.next() {
collectedReturn +=val
}
return collectedReturn }
print("val is \(something)") // prints val is abcdef
- withThrowingTaskGroup - can throw Errors, grp conforms to AsyncSequence, so return value could be collated by
for try await
loop orwhile let item = try await grp.next()
ortry await grp.reduce(initial, transform)
..waitForAll()
will discard the result though. -- returnValue for each Task within the group should be the same representingtry await withTaskGroup([Model].self)
but overall group could return a different data type as well with collated Task results.
func loadStories() async {
do {
let allStories = try await withThrowingTaskGroup(of: [Model].self) { grp -> [Model] in
for i in 1...5 {
grp.addTask {
let url = URL(string: "URL")!
let (data, _) = try await URLSession.shared.data(from: url)
_//if Task.isCancelled { return []}_
return try JSONDecoder().decode([Model].self, from: data)
}
}
_//grp.cancelAll()_
//return try await grp.reduce(into: [Model]()) { $0 += $1 }
var collectedItems = [Model]()
while let item = try await grp.next() {
collectedItems.append(contentsOf: item)
}
return collectedItems
}
newsItems = allStories.sorted {
$0.id < $1.id
}
} catch let error {
if error as! CancelError == CancelError.Icancelled {
print("I cancelled")
}
print("Error \(error.localizedDescription)")
}
}
Task Cancellation:
.cancelAll()
Method on grp, wont cancel unless check for cancellation is cooperative but seems to work even otherwise, meaning check for cancellation such asif Task.isCancelled
ortry Task.checkCancellation
calls within the grp's individual task as shown above in the comments.Heterogenous Return type for each task in Taskgroup is possible with wrapping up actual return type with enum so that each task can return same enum with different case having different associated value type. And still, taskGroup can ultimately return different data type as well.
My Notes as understood from HackingWithSwift Structured Concurrency series.
Top comments (0)