[swift-evolution] [Concurrency] modifying beginAsync, suspendAsync to support cancellation
Howard Lovatt
howard.lovatt at gmail.com
Mon Aug 28 20:42:21 CDT 2017
I think this makes the proposed async/await coroutines more viable.
Building on this, if the proposed Cancelable became:
protocol ExecutionControl {
/// Causes the executing coroutine to throw
`TerminateCoroutine.cancelled` and also terminates all the sub-coroutines.
var isCancelled: Bool { set }
/// If an await exceeds timeout then executing task throws
`TerminateCoroutine.timeout` and also terminates all the sub-coroutines.
var timeout: DispatchTimeInterval { get set }
}
Then async/await coroutine would have feature parity with a typical
`Future` - which would be good.
PS Effectively the execution service is returning the `Future`!
-- Howard.
On 29 August 2017 at 09:42, Marc Schlichte via swift-evolution <
swift-evolution at swift.org> wrote:
>
> Am 19.08.2017 um 20:33 schrieb Marc Schlichte via swift-evolution <
> swift-evolution at swift.org>:
>
> Hi,
>
> to support cancellation, I propose the following changes to `beginAsync()`
> and `suspendAsync()`:
>
> `beginAsync()` returns an object adhering to a `Cancelable` protocol:
>
> ```
> func beginAsync(_ body: () async throws-> Void) rethrows -> Cancelable
>
> protocol Cancelable { func cancel() }
> ```
>
> `suspendAsync()` takes a new thunk parameter:
>
> ```
> func suspendAsync<T>(onCancel: () -> Void, body: (cont: (T) -> Void, err:
> (Error) -> Void) async -> T
> ```
>
> Now, when `cancel()` is invoked, the `onCancel` thunk in the current
> suspension (if any) will be called.
>
>
>
> Example:
>
> ```
> var task: Cancelable?
>
> @IBAction func buttonDidClick(sender: AnyObject) {
> task = beginAsync {
> do {
> let image = try await processImage()
> imageView.image = image
> } catch AsyncError.canceled {
> imageView.image = nil // or some fallback image...
> } catch {
> // other handling
> }
> }
> )
>
> @IBAction func cancelDidClick(sender: AnyObject) {
> task?.cancel()
> }
>
>
> Just adding here that instead of directly using the low-level
> `beginAsync`, a Future/Promise could be used instead:
>
> ```
> var task: Future<UIImage>?
>
> @IBAction func buttonDidClick(sender: AnyObject) {
> task = Future {
> try await processImage()
> }
> do {
> imageView.image = try await task!.get()
> } catch AsyncError.canceled {
> imageView.image = nil // or some fallback image...
> } catch {
> // other handling
> }
> }
>
> @iBAction func cancelDidClick(sender: AnyObject) {
> task?.cancel()
> }
> ```
>
> Of course, the init of Future would have to be changed
>
> convenience init(_ body: () throws async -> T) {
> self.init()
> task = beginAsync {
> do {
> self.fulfill(try await body())
> } catch {
> self.fail(error)
> }
> }
> }
>
> (BTW also added missing throws and try in code above)
>
> and `cancel()` would have to be added to `Future`:
>
> ```
> public func cancel() {
> task?.cancel()
> }
>
> ```
>
>
> func processImage() async throws -> UIImage {
> // This processing should be on a background queue (or better an Actor
> :-) - but ignored for this example
> var cancelled = false
> suspendAsync(onCancel: {
>
> cancelled = true
> }, body: { cont, err in
> while !done && !cancelled {
> // do the processing on image until done or canceled
> }
> guard !cancelled else { err(AsyncError.canceled) } // BTW, maybe
> change signature of `suspendAsync` to allow to throw here instead
> cont(image)
> }
> }
> ```
>
>
> ^ BTW, this should be `return await suspendAsync(…`
>
>
> Cheers
> Marc
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170829/3df72fdd/attachment.html>
More information about the swift-evolution
mailing list