[swift-evolution] [Concurrency] async/await + actors: cancellation
David P Grove
groved at us.ibm.com
Fri Aug 18 10:21:35 CDT 2017
> From: Jan Tuitman via swift-evolution <swift-evolution at swift.org>
> To: swift-evolution at swift.org
> Date: 08/18/2017 02:54 AM
> Subject: [swift-evolution] [Concurrency] async/await + actors:
cancellation
> Sent by: swift-evolution-bounces at swift.org
>
> Hi,
>
>
> After reading Chris Lattners proposal for async/await I wonder if
> the proposal has any way to cancel outstanding tasks.
>
> I saw these two:
>
> @IBAction func buttonDidClick(sender:AnyObject) {
> // 1
> beginAsync {
> // 2
> let image = await processImage()
> imageView.image = image
> }
> // 3
> }
>
>
> And:
>
> /// Shut down the current coroutine and give its memory back to the
> /// shareholders.
> func abandon() async -> Never {
> await suspendAsync { _ = $0 }
> }
>
>
> Now, if I understand this correctly, the second thing is abandoning
> the task from the context of the task by basically preventing the
> implicit callback of abandon() to ever be called.
>
> But I don't see any way how the beginAsync {} block can be canceled
> after a certain amount of time by the synchronous thread/context
> that is running at location //3
>
> shouldn't beginAsync return something which can be checked if the
> block passed in to it is finished/ waiting/ ...? and which has a
> method to cancel it?
> I know Thread.cancel (which existed in some programming languages)
> is evil because you never know where it stops, but it seems strange
> to me, that there is no way to communicate with the running process
in //2.
>
> Then there is this example:
>
> func processImageData() async throws -> Image {
> startProgressBar()
> defer {
> // This will be called when error is thrown, when all operations
> // complete and a result is returned, or when the coroutine is
> // abandoned. We don't want to leave the progress bar animating if
> // work has stopped.
> stopProgressBar()
> }
>
> let dataResource = try await loadWebResource("dataprofile.txt")
> let imageResource = try await loadWebResource("imagedata.dat")
> do {
> let imageTmp = try await decodeImage(dataResource, imageResource)
> } catch _ as CorruptedImage {
> // Give up hope now.
> await abandon()
> }
> return try await dewarpAndCleanupImage(imageTmp)
> }
>
>
> this seems to wrap other asynchronous functions in a new async
> function so it can add the defer logic and abandon logic, but this
> seems to me only adding more checking of the spawned process and
> thus not sufficient enough to deal with an external reason in
> location //3 (for example the process running //3 receives an event
> that the app is about to be quitted).
>
> so I am a bit confused here, am I missing something? How would //2
> be canceled from location //3, or how would //3 trigger an
> abandoment inside //2 ?
>
My initial reading is that cancellation is not part of the async/await
design. I think this is the right decision. (I hope I am right ;) ).
First the semantics of arbitrary cancellation are problematic (as you
noted); it is really hard to write reliable code when a thread of control
could be spontaneously killed at any program point but the program as a
whole still needs to be able to continue to operate). Second, support for
cancellation imposes a significant implementation burden. It implies that
you actually need to make individual tasks into real program-visible
entities and that can get in the way of high-performance implementation
techniques (which Chris alludes to as perhaps being needed in Swift 6/7/8
for an actor system to really become viable at scale).
Much more reasonable to allow the programmer to plumb in cancellation where
it is needed via shared state that can be checked at safely cancelable
points in the task.
regards,
--dave
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170818/f0b06aad/attachment.html>
More information about the swift-evolution
mailing list