Explore structured concurrency in Swift

RSS for tag

Discuss the WWDC21 session Explore structured concurrency in Swift.

Posts under wwdc21-10134 tag

5 Posts

Post

Replies

Boosts

Views

Activity

I'm unable to use the withTaskCancellaionHandler without a static analysis error
Hi, We have an API that I'm trying to prototype some async await extensions for. Most of our asynchronous methods are cancelable by returning an object that implements our AGSCancelable protocol that includes a cancel() method. Here's the code I have to try to extend a geocoding method on our AGSLocatorTask class: extension AGSLocatorTask { func geocode(withSearchText text: String) async throws -> [AGSGeocodeResult] { typealias GeocodeContinuation = CheckedContinuation<[AGSGeocodeResult], Error> var cancelable: AGSCancelable? return try await withTaskCancellationHandler(handler: { cancelable?.cancel() }, operation: { return try await withCheckedThrowingContinuation({ (continuation: GeocodeContinuation) in cancelable = self.geocode(withSearchText: text) { results, error in if let error = error { continuation.resume(throwing: error) } else { continuation.resume(returning: results!) } } }) }) } } This works great, but I have to comment out the cancelable?.cancel() call or else I get a Reference to captured var 'cancelable' in concurrently-executing code static analysis error (see attached screenshot). Could someone explain how to fix this, or is this a bug in the Xcode beta? Many thanks, and thanks for a great WWDC!!
4
0
1.8k
Dec ’21
Swift Concurrency (async let) - Cancellation
I am a bit confused about tasks being cancelled. Overview: checkCancellation function has 2 child tasks: computeA and computeB that run concurrently, computeB throws an error. Doubt: I expected child task computeA to be cancelled because computeB threw an error, but computeA was never cancelled. Is my understanding wrong or am I missing something? Or is this a bug? Note: I am using a SwiftUI project (as Swift Playgrounds don't support async let) macOS Big Sur 11.5.2 (20G95) Xcode Version 13.0 beta 5 (13A5212g) Output: A - started B - going to throw A - going to return, Task.isCancelled = false error: infinity Concurrent Function Definitions: import Foundation import UIKit enum ComputationError: Error { case infinity } fileprivate func computeA() async throws -&gt; Int { print("A - started") await Task.sleep(2 * 100_000_000) print("A - going to return, Task.isCancelled = \(Task.isCancelled)") //I expected Task.isCancelled to be true return 25 } fileprivate func computeB() async throws -&gt; Int { print("B - going to throw") throw ComputationError.infinity } func checkCancellation() async throws { async let a = computeA() async let b = computeB() let c = try await a + b print("c = \(c)") } Invoking Concurrent function struct ContentView: View { var body: some View { Button("check cancellation") { Task { do { try await checkCancellation() print("normal exit") } catch { print("error: \(error)") } } } } }
4
0
1.4k
Dec ’21
Async/let producing error in playground? Xcode 13.0 beta
I'm seeing an error trying to test out async let. It seems like this should work, based on the async/let and structured concurrency session videos. Here's the code: func doIt() async -> String {     let t = TimeInterval.random(in: 0.25 ... 2.0)     Thread.sleep(forTimeInterval: t)     return String("\(Double.random(in: 0...1000))") } async {     async let a = doIt()     async let b = doIt()     async let c = doIt()     async let d = doIt()     let results = await [a, b, c, d]     for result in results {         print("  \(result)")     } } But, I get this error for every "async let" statement: error: AsyncLetSwift55WWDC21.playground:12:15: error: expression is 'async' but is not marked with 'await' async let a = doIt() ^ await Am I missing something key, or is this a bug? I'm running this in the Xcode 13.0 beta, in a Playground. Thanks!!
12
0
4.4k
Aug ’21
withThrowingTaskGroup - (un)expected progress behavior?
I'm trying to use the new structured concurrency features of Swift 5.5 to update some code in a larger App that has been written using GCD. One routine is loading parts of a dataset in a parallel loop and I would like to convert this code using withThrowingTaskGroup while keeping a progress counter. The code compiles, runs, but does not update the progress in a way I expected: var progressCounter = 0 let count = 500 try await withThrowingTaskGroup(of: Void.self) { group in for idx in 0..<count { _ = group.addTaskUnlessCancelled { // some IO } } for try await _ in group { progressCounter += 1 } } The for try await loop is executed after all 500 task have been run and finished (iOS 15 Beta 5). I was under the impression, the for try await loop would be run in parallel to the tasks, collecting results as they come in and thereby updating the progress counter. Clearly I'm missing something or is this expected? Is withThrowingTaskGroup not the right tool for this? Any insight would be appreciated.
2
0
1.2k
Aug ’21
TaskGroup in and Actor
I've had an issue in my project where I trigger a task from a SwiftUI View with the modifier .task. From there it calls and async function into an actor that has a TaskGroup that makes concurrent network calls that has a type of Void.self. I've noticed that sometimes the TaskGroup is either never called and will no longer be called. I'm wondering if perhaps a TaskGroup inside of an Actor that has a parent Task created outside the Actor is a problem? But it does seem to work if I change the Actor to a Class. Could someone help explain to me why this is?
0
0
685
Aug ’21
I'm unable to use the withTaskCancellaionHandler without a static analysis error
Hi, We have an API that I'm trying to prototype some async await extensions for. Most of our asynchronous methods are cancelable by returning an object that implements our AGSCancelable protocol that includes a cancel() method. Here's the code I have to try to extend a geocoding method on our AGSLocatorTask class: extension AGSLocatorTask { func geocode(withSearchText text: String) async throws -> [AGSGeocodeResult] { typealias GeocodeContinuation = CheckedContinuation<[AGSGeocodeResult], Error> var cancelable: AGSCancelable? return try await withTaskCancellationHandler(handler: { cancelable?.cancel() }, operation: { return try await withCheckedThrowingContinuation({ (continuation: GeocodeContinuation) in cancelable = self.geocode(withSearchText: text) { results, error in if let error = error { continuation.resume(throwing: error) } else { continuation.resume(returning: results!) } } }) }) } } This works great, but I have to comment out the cancelable?.cancel() call or else I get a Reference to captured var 'cancelable' in concurrently-executing code static analysis error (see attached screenshot). Could someone explain how to fix this, or is this a bug in the Xcode beta? Many thanks, and thanks for a great WWDC!!
Replies
4
Boosts
0
Views
1.8k
Activity
Dec ’21
Swift Concurrency (async let) - Cancellation
I am a bit confused about tasks being cancelled. Overview: checkCancellation function has 2 child tasks: computeA and computeB that run concurrently, computeB throws an error. Doubt: I expected child task computeA to be cancelled because computeB threw an error, but computeA was never cancelled. Is my understanding wrong or am I missing something? Or is this a bug? Note: I am using a SwiftUI project (as Swift Playgrounds don't support async let) macOS Big Sur 11.5.2 (20G95) Xcode Version 13.0 beta 5 (13A5212g) Output: A - started B - going to throw A - going to return, Task.isCancelled = false error: infinity Concurrent Function Definitions: import Foundation import UIKit enum ComputationError: Error { case infinity } fileprivate func computeA() async throws -&gt; Int { print("A - started") await Task.sleep(2 * 100_000_000) print("A - going to return, Task.isCancelled = \(Task.isCancelled)") //I expected Task.isCancelled to be true return 25 } fileprivate func computeB() async throws -&gt; Int { print("B - going to throw") throw ComputationError.infinity } func checkCancellation() async throws { async let a = computeA() async let b = computeB() let c = try await a + b print("c = \(c)") } Invoking Concurrent function struct ContentView: View { var body: some View { Button("check cancellation") { Task { do { try await checkCancellation() print("normal exit") } catch { print("error: \(error)") } } } } }
Replies
4
Boosts
0
Views
1.4k
Activity
Dec ’21
Async/let producing error in playground? Xcode 13.0 beta
I'm seeing an error trying to test out async let. It seems like this should work, based on the async/let and structured concurrency session videos. Here's the code: func doIt() async -> String {     let t = TimeInterval.random(in: 0.25 ... 2.0)     Thread.sleep(forTimeInterval: t)     return String("\(Double.random(in: 0...1000))") } async {     async let a = doIt()     async let b = doIt()     async let c = doIt()     async let d = doIt()     let results = await [a, b, c, d]     for result in results {         print("  \(result)")     } } But, I get this error for every "async let" statement: error: AsyncLetSwift55WWDC21.playground:12:15: error: expression is 'async' but is not marked with 'await' async let a = doIt() ^ await Am I missing something key, or is this a bug? I'm running this in the Xcode 13.0 beta, in a Playground. Thanks!!
Replies
12
Boosts
0
Views
4.4k
Activity
Aug ’21
withThrowingTaskGroup - (un)expected progress behavior?
I'm trying to use the new structured concurrency features of Swift 5.5 to update some code in a larger App that has been written using GCD. One routine is loading parts of a dataset in a parallel loop and I would like to convert this code using withThrowingTaskGroup while keeping a progress counter. The code compiles, runs, but does not update the progress in a way I expected: var progressCounter = 0 let count = 500 try await withThrowingTaskGroup(of: Void.self) { group in for idx in 0..<count { _ = group.addTaskUnlessCancelled { // some IO } } for try await _ in group { progressCounter += 1 } } The for try await loop is executed after all 500 task have been run and finished (iOS 15 Beta 5). I was under the impression, the for try await loop would be run in parallel to the tasks, collecting results as they come in and thereby updating the progress counter. Clearly I'm missing something or is this expected? Is withThrowingTaskGroup not the right tool for this? Any insight would be appreciated.
Replies
2
Boosts
0
Views
1.2k
Activity
Aug ’21
TaskGroup in and Actor
I've had an issue in my project where I trigger a task from a SwiftUI View with the modifier .task. From there it calls and async function into an actor that has a TaskGroup that makes concurrent network calls that has a type of Void.self. I've noticed that sometimes the TaskGroup is either never called and will no longer be called. I'm wondering if perhaps a TaskGroup inside of an Actor that has a parent Task created outside the Actor is a problem? But it does seem to work if I change the Actor to a Class. Could someone help explain to me why this is?
Replies
0
Boosts
0
Views
685
Activity
Aug ’21