<html><body><p><tt><font size="2">&gt; From: Jan Tuitman via swift-evolution &lt;swift-evolution@swift.org&gt;</font></tt><br><tt><font size="2">&gt; To: swift-evolution@swift.org</font></tt><br><tt><font size="2">&gt; Date: 08/18/2017 02:54 AM</font></tt><br><tt><font size="2">&gt; Subject: [swift-evolution] [Concurrency] async/await + actors: cancellation</font></tt><br><tt><font size="2">&gt; Sent by: swift-evolution-bounces@swift.org</font></tt><br><tt><font size="2">&gt; <br>&gt; Hi,<br>&gt; <br>&gt; <br>&gt; After reading Chris Lattners proposal for async/await I wonder if <br>&gt; the proposal has any way to cancel outstanding tasks.<br>&gt; <br>&gt; I saw these two:<br>&gt; <br>&gt; @IBAction func buttonDidClick(sender:AnyObject) {<br>&gt; &nbsp; // 1<br>&gt; &nbsp; beginAsync {<br>&gt; &nbsp; &nbsp; // 2<br>&gt; &nbsp; &nbsp; let image = await processImage()<br>&gt; &nbsp; &nbsp; imageView.image = image<br>&gt; &nbsp; }<br>&gt; &nbsp; // 3<br>&gt; } <br>&gt; <br>&gt; <br>&gt; And:<br>&gt; <br>&gt; /// Shut down the current coroutine and give its memory back to the<br>&gt; /// shareholders.<br>&gt; func abandon() async -&gt; Never {<br>&gt; &nbsp; await suspendAsync { _ = $0 }<br>&gt; }<br>&gt; <br>&gt; <br>&gt; Now, if I understand this correctly, the second thing is abandoning <br>&gt; the task from the context of the task by basically preventing the <br>&gt; implicit callback of abandon() to ever be called.<br>&gt; <br>&gt; But I don't see any way how the beginAsync {} block can be canceled <br>&gt; after a certain amount of time by the synchronous thread/context <br>&gt; that is running at location //3<br>&gt; <br>&gt; shouldn't beginAsync return something which can be checked if the <br>&gt; block passed in to it is finished/ waiting/ ...? and which has a <br>&gt; method to cancel it?<br>&gt; I know Thread.cancel (which existed in some programming languages) <br>&gt; is evil because you never know where it stops, but it seems strange <br>&gt; to me, that there is no way to communicate with the running process in //2.<br>&gt; <br>&gt; Then there is this example:<br>&gt; <br>&gt; func processImageData() async throws -&gt; Image {<br>&gt; &nbsp; startProgressBar()<br>&gt; &nbsp; defer {<br>&gt; &nbsp; &nbsp; // This will be called when error is thrown, when all operations<br>&gt; &nbsp; &nbsp; // complete and a result is returned, or when the coroutine is<br>&gt; &nbsp; &nbsp; // abandoned. We don't want to leave the progress bar animating if<br>&gt; &nbsp; &nbsp; // work has stopped.<br>&gt; &nbsp; &nbsp; stopProgressBar()<br>&gt; &nbsp; }<br>&gt; <br>&gt; let dataResource &nbsp;= try await loadWebResource(&quot;dataprofile.txt&quot;)<br>&gt; &nbsp; let imageResource = try await loadWebResource(&quot;imagedata.dat&quot;)<br>&gt; &nbsp; do {<br>&gt; &nbsp; &nbsp; let imageTmp &nbsp; &nbsp;= try await decodeImage(dataResource, imageResource)<br>&gt; &nbsp; } catch _ as CorruptedImage {<br>&gt; &nbsp; &nbsp; // Give up hope now.<br>&gt; &nbsp; &nbsp; await abandon()<br>&gt; &nbsp; }<br>&gt; &nbsp; return try await dewarpAndCleanupImage(imageTmp)<br>&gt; }<br>&gt; <br>&gt; <br>&gt; this seems to wrap other asynchronous functions in a new async <br>&gt; function so it can add the defer logic and abandon logic, but this <br>&gt; seems to me only adding more checking of the spawned process and <br>&gt; thus not sufficient enough to deal with an external reason in <br>&gt; location //3 (for example the process running //3 receives an event <br>&gt; that the app is about to be quitted). <br>&gt; <br>&gt; so I am a bit confused here, am I missing something? How would //2 <br>&gt; be canceled from location //3, or how would //3 trigger an <br>&gt; abandoment inside //2 ?<br>&gt; <br></font></tt><br><tt><font size="2">My initial reading is that cancellation is not part of the async/await design. &nbsp;I think this is the right decision. &nbsp;(I hope I am right ;) ). </font></tt><br><br><tt><font size="2">First the semantics of arbitrary cancellation are problematic (as you noted); &nbsp;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). &nbsp;Second, support for cancellation imposes a significant implementation burden. &nbsp;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).</font></tt><br><br><tt><font size="2">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.</font></tt><br><br><tt><font size="2">regards,</font></tt><br><br><tt><font size="2">--dave</font></tt><br><BR>
</body></html>