[Concurrency] async/await + actors

Because async/await serve a different (but related) purpose than background threads. Remember that concurrency is not parallelism: running in parallel in the background is a useful construction, but not the *only* construction.

If you have multiple tasks you’d like to kick off in parallel, async/await can support that by providing some kind of awaitable Future object. You’d then call multiple functions that return those futures and then await on the completion of all of the Futures (Future.gatherResults is a nice function name).

However, async/await also allows you to more directly handle the notion that you are making a single blocking call that you need the result of before your computation can complete. For example, if you only had to load *one* web resource instead of two, your code with async/await would look exactly like synchronous code with the word ‘await’ scattered around:

func doit() async throws {
    let dataResource = await loadWebResource(“dataprofile.txt”)
    let imageTmp = decodeImage(dataResource)
    return dewarpAndCleanupImage(imageTmp)
}

At this point scheduling this function becomes the calling programmer’s concern. It also allows multiple calls to doit() to be interleaved without deferring them to background threads and relying on the OS scheduler to schedule them appropriately. This is very useful on server-side applications that do not want to be dispatching large numbers of threads, and that are likely already running an I/O select() loop that can handle the most common cause of awaits (namely, please do this I/O).

For functions that are computationally heavy, no problem: most languages provide built-in support for scheduling async functions into threadpools and providing a Future that completes on the completion of the background task.

I guess the TL;DR here is that async/await allows you to have concurrency with or without parallelism, while using thread pools means you can only have concurrency with parallelism.

Cory

···

On 11 Sep 2017, at 00:10, Howard Lovatt via swift-evolution <swift-evolution@swift.org> wrote:

Not really certain what async/await adds, using this library (note self promotion) which is built on top of GCD:

GitHub - hlovatt/Concurrency-Utilities: Atomics, Futures, and Reactive-Streams for Swift

You can write:

    func doit() {
        AsynchronousFuture { // Executes in background and therefore does not block main
            let dataResource = loadWebResource("dataprofile.txt") // Returns a future and therefore runs concurrently in background.
            let imageResource = loadWebResource("imagedata.dat") // Future therefore concurrent.
            let imageTmp = decodeImage(dataResource.get ?? defaultText, imageResource.get ?? defaultData) // Handles errors with defaults easily, including timeout.
            let imageResult = dewarpAndCleanupImage(imageTmp)
            Thread.executeOnMain {
                self.imageResult = imageResult
            }
        }
    }

So why bother with async/await?