Slide 1

Slide 1 text

Concurrency Manifesto: async/await, actors, iOS Teddy Ku
 github.com/tkuichooseyou

Slide 2

Slide 2 text

How do we handle concurrency in iOS?

Slide 3

Slide 3 text

It’s almost 2018! • iPhone X: 6 cores, 3 GB RAM • Multi-core, multi-thread apps • Scalable, Distributed applications https://farm8.staticflickr.com/7403/16384510489_1cda4743b5_o.jpg

Slide 4

Slide 4 text

Concurrency in Swift 4 func processImageData1(completionBlock: (result: Image) -> Void) { loadWebResource("dataprofile.txt") { dataResource in loadWebResource("imagedata.dat") { imageResource in decodeImage(dataResource, imageResource) { imageTmp in dewarpAndCleanupImage(imageTmp) { imageResult in completionBlock(imageResult) } } } } }

Slide 5

Slide 5 text

Concurrency in Swift 4 • Completion blocks • Queues, Threads • Mutex, Semaphore • GCD: dispatch_barrier

Slide 6

Slide 6 text

Problems • Ambiguous queue • Hard to read • Deadlocks • Race conditions Bugs

Slide 7

Slide 7 text

what to do? futures/ promises channels coroutines Venice

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Build a flexible foundation. Let community build libraries

Slide 10

Slide 10 text

Step 1: async/await

Slide 11

Slide 11 text

async/await func loadWebResource(_ path: String) async -> Resource func decodeImage(_ r1: Resource, _ r2: Resource) async -> Image func dewarpAndCleanupImage(_ i : Image) async -> Image func processImageData1() async -> Image { let dataResource = await loadWebResource("dataprofile.txt") let imageResource = await loadWebResource("imagedata.dat") let imageTmp = await decodeImage(dataResource, imageResource) let imageResult = await dewarpAndCleanupImage(imageTmp) return imageResult }

Slide 12

Slide 12 text

async/await func loadWebResource(_ path: String) async -> Resource func processImageData1() async -> Image { let dataResource = await loadWebResource("dataprofile.txt") // ... } • async: the func can suspend before returning a value (is a coroutine) • await: noop, but shows coder that non-local control flow can happen

Slide 13

Slide 13 text

Step 1: async/await ✅

Slide 14

Slide 14 text

What about handling multiple async things network requests, caching, image processing, etc?

Slide 15

Slide 15 text

Step 2: Actors
 Eliminating shared mutable state

Slide 16

Slide 16 text

Actors: in Swift 1. DispatchQueue 2. Data that queue protects 3. Messages that can be run on that queue
 
 `actor`: reference type, like `class`. Can conform to protocols

Slide 17

Slide 17 text

Do not communicate by sharing memory; instead, share memory by communicating
 - Effective Go

Slide 18

Slide 18 text

actors actor TableActor { let mainActor : TheMainActor var theList : [String] = [] { didSet { mainActor.updateTableView(theList) } } init(mainActor: TheMainActor) { self.mainActor = mainActor } // this checks to see if all the entries in the list are capitalized: // if so, it capitalize the string before returning it to encourage // capitalization consistency in the list. func prettify(_ x : String) -> String { // Details omitted: it inspects theList, adjusting the // string before returning it if necessary. } actor func add(entry: String) { theList.append(prettify(entry)) } }

Slide 19

Slide 19 text

actors actor TableActor { let mainActor : TheMainActor var theList : [String] = [] { didSet { mainActor.updateTableView(theList) } }
 
 func prettify(_ x : String) -> String {} actor func add(entry: String) { theList.append(prettify(entry)) } } // 1. send message to Table actor tableActor.add(entry: “foo") // 2. Table actor modifies its own data // 3. Table actor sends message to Main actor with copied data
 // 4. Main actor refreshes table view

Slide 20

Slide 20 text

actors • TableActor’s data: reference to mainActor, and theList • actor can send messages to any other actor • actor methods are the messages that actors accept • actor methods are implicitly async, so they can freely call async methods and await their results • An actor method cannot return a value, throw an error, or have an inout parameter. • Actor method parameters must produce independent values when copied • Local state and non-actor methods may only be accessed by methods defined lexically on the actor or in an extension to it (whether they are marked actor or otherwise) actor func add(entry: String) mainActor.updateTableView(theList)

Slide 21

Slide 21 text

We already have libraries, why do we need async/ await + actors?

Slide 22

Slide 22 text

• Compiler optimization • detect deadlocks • optimize ARC retain/release calls • Better debugging • Spread knowledge First-class concurrency model benefits

Slide 23

Slide 23 text

Example: Image Caching

Slide 24

Slide 24 text

Before: completion block on DispatchQueue.main @objc final class RemoteImageManager: NSObject { static func downloadImage(with url: URL, mainQueueCompletion completion: @escaping PINRemoteImageManagerImageCompletion) -> UUID? { return PINRemoteImageManager.shared().downloadImage(with: url, options: [], completion: { (result: PINRemoteImageManagerResult) in DispatchQueue.main.async { completion(result) } }) } }

Slide 25

Slide 25 text

After: RemoteImageActor actor RemoteImageActor { // implicitly private let cache: ImageCache actor func downloadImage(with url: URL) -> RemoteImageManagerResult { // urlSession stuff // handle updating cache without mutex/locks because this actor has exclusive access } } class ViewController: UIViewContoller { private var remoteImageActor: RemoteImageActor!
 private var imageViewActor: ImageViewActor! private func updateBackground() { let dogeImage = await remoteImageActor.downloadImage(with: "doge.gif") let processedImage = await imageProcessorActor.scale(0.5, image: dogeImage) imageViewActor.updateImageView(with image: dogeImage) } }

Slide 26

Slide 26 text

Actor benefits • clearly express which queue is running • avoid mutex/locks • avoid programmer error

Slide 27

Slide 27 text

Still to come • Reliability through fault isolation • fire and forget actor messages • add error handling in Actor init, not scattered everywhere • handle failures by restarting actor, etc. • Improving system architecture • declarative, clean interprocess communication • `distributed` keyword

Slide 28

Slide 28 text

Let’s learn from other languages/libraries

Slide 29

Slide 29 text

Thank you!