I have two situations that I’m not quite sure how to best write using the new Swift concurrency features. It’s in a Vapor code base, but this isn’t really tied to Vapor.
I’m not quite sure whether a TaskGroup
is the right thing to do or async let
. Or is there some other way that I’m missing here? What is the best and/or idiomatic way to do this?
The two situations are:
1. An async
method that kicks off two other async
calls and then returns when both are done
Here’s what I came up with for the two versions:
func runTwoThingsUsingTaskGroup() async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask { try await self.work1() }
group.addTask { try await self.work2() }
try await group.waitForAll() // If any of the two parallel tasks throws an error, the whole method throws
}
}
func runTwoThingsUsingAsyncLet() async throws {
async let result1 = self.work1()
async let result2 = self.work2()
(_, _) = try await (result1, result2) // If any of the two parallel tasks throws an error, the whole method throws
}
2. An async
method that kicks off two other async
calls and then returns the result of one of them
Old code
I think thought it’s possible to use a TaskGroup
for this, but it’s… not pretty. Or I’m missing something here:
Edit: This doesn’t compile because: Mutation of captured var 'finalResult' in concurrently-executing code
func runTwoThingsUsingTaskGroupWithResult() async throws -> Value {
return try await withThrowingTaskGroup(of: Void.self, returning: Value.self) { group in
var finalResult: Value?
group.addTask { finalResult = try await self.work1() }
group.addTask { try await self.work2() }
try await group.waitForAll() // If any of the two parallel tasks throws an error, the whole method throws
return finalResult!
}
}
Here’s what I came up with in a async let
variant:
func runTwoThingsUsingAsyncLetWithResult() async throws -> Value {
async let result1 = self.work1()
async let result2 = self.work2()
let (finalResult, _) = try await (result1, result2).0 // If any of the two parallel tasks throws an error, the whole method throws
return finalResult
}