Slide 1

Slide 1 text

Coroutines, Threads and Communication Bob Dahlberg Mobile Lead Developer

Slide 2

Slide 2 text

Coroutines are lightweight threads “

Slide 3

Slide 3 text

Lightweight Coroutines Let’s test lightweight first.

Slide 4

Slide 4 text

Lightweight Coroutines Let’s test lightweight first. fun main() = runBlocking { repeat(100_000) { launch { !// creates a coroutine println(“On thread !-> $thread”) } } }

Slide 5

Slide 5 text

Lightweight Coroutines Let’s test lightweight first. repeat(100_000) { launch { !// creates a coroutine println(“On thread !-> $thread”) } } !// on main thread

Slide 6

Slide 6 text

Lightweight Coroutines Let’s test lightweight first. !// on main thread repeat(100_000) { thread { !// creates a thread println(“On thread !-> $thread”) } }

Slide 7

Slide 7 text

Lightweight Dispatchers Coroutines Let’s test lightweight first. !// on main thread repeat(100_000) { launch(Dispatchers.Default) { println(“On thread !-> $thread”) } }

Slide 8

Slide 8 text

Lightweight Dispatchers Coroutines Let’s test lightweight first. !// on main thread repeat(100_000) { launch(Dispatchers.IO) { println(“On thread !-> $thread”) } }

Slide 9

Slide 9 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety

Slide 10

Slide 10 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety !// on main thread var i = 0 repeat(100_000) { launch(Dispatchers.Default) { i!++ } } println(“Result !-> $i”)

Slide 11

Slide 11 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety !// on main thread var i = 0 repeat(100_000) { launch(Dispatchers.Default) { i!++ } } println(“Result !-> $i”) Output: Result !-> 85325

Slide 12

Slide 12 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety !// on main thread var i = 0 repeat(100_000) { launch(Dispatchers.IO) { i!++ } } println(“Result !-> $i”) Output: Result !-> 78332

Slide 13

Slide 13 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety !// on main thread var i = 0 repeat(100_000) { launch { i!++ } } println(“Result !-> $i”) Output: Result !-> 100000

Slide 14

Slide 14 text

Lightweight Dispatchers Thread safety Coroutines Let’s take a detour around thread safety !// on main thread var i = 0 launch(Dispatchers.Default) { repeat(100_000) { launch { i!++ } } } println(“Result !-> $i”) Output: Result !-> 92342

Slide 15

Slide 15 text

Lightweight Dispatchers Thread safety Threads? Coroutines Coroutines are lightweight threads lightweight

Slide 16

Slide 16 text

Lightweight Dispatchers Thread safety Threads? Coroutines Coroutines are threads

Slide 17

Slide 17 text

Lightweight Dispatchers Thread safety Threads? Coroutines Coroutines are threads !// on main thread launch(Dispatchers.Unconfined) { println(“A1. On thread $thread”) delay(200) println(“A2. On thread $thread”) } Output: A1. On thread main A2. On thread worker-1

Slide 18

Slide 18 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread launch(Dispatchers.IO) { println(“A1. On thread $thread”) switchContext() println(“A2. On thread $thread”) } suspend fun switchContext() { withContext(Dispatchers.Default) { println(“B1. Switching $thread”) } } Output: A1. On thread worker-1 B1. Switching worker-1 A2. On thread worker-1

Slide 19

Slide 19 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread launch(Dispatchers.IO) { println(“A1. On thread $thread”) switchContext() println(“A2. On thread $thread”) } suspend fun switchContext() { withContext(Dispatchers.Default) { println(“B1. Switching $thread”) } } Output: A1. On thread worker-1 B1. Switching worker-3 A2. On thread worker-3

Slide 20

Slide 20 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread val local = ThreadLocal() launch(Dispatchers.IO) { local.set(“IO") println(“A1. ${local.get()}”) switchContext() println(“A2. ${local.get()}”) } suspend fun switchContext() { withContext(Dispatchers.Default) { println(“B1. ${local.get()}”) local.set(“Default") } } Output: A1. IO B1. IO A2. Default

Slide 21

Slide 21 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread val local = ThreadLocal() launch(Dispatchers.IO) { local.set(“IO") println(“A1. ${local.get()}”) switchContext() println(“A2. ${local.get()}”) } suspend fun switchContext() { withContext(Dispatchers.Default) { println(“B1. ${local.get()}”) local.set(“Default") } } Output: A1. IO B1. null A2. Default

Slide 22

Slide 22 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread @Synchronized fun critical() { println(“Start $thread”) Thread.sleep(100) println(“Stop $thread”) } repeat(2) { thread { critical() } } Output: Start worker-1 Stop worker-1 Start worker-3 Stop worker-3

Slide 23

Slide 23 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread @Synchronized suspend fun critical() { println(“Start $thread”) delay(100) println(“Stop $thread”) } repeat(2) { launch(Dispatchers.Default) { critical() } } Output: Start worker-1 Start worker-3 Stop worker-1 Stop worker-3

Slide 24

Slide 24 text

Lightweight Dispatchers Thread safety Threads? Coroutines !// on main thread suspend fun critical() { synchronized(obj) { println(“Start $thread”) delay(100) println(“Stop $thread”) } } repeat(2) { launch(Dispatchers.Default) { critical() } } Output: Start worker-1 Start worker-3 Stop worker-1 Stop worker-3 The 'delay' suspension point is inside a critical section

Slide 25

Slide 25 text

Key take aways

Slide 26

Slide 26 text

coroutines !== lightweight

Slide 27

Slide 27 text

coroutines !!= threads

Slide 28

Slide 28 text

dispatchers !!= thread pools

Slide 29

Slide 29 text

How to communicate coroutine-style

Slide 30

Slide 30 text

Deferred Communicate Deferred is a non-blocking cancelable future
 val result: Deferred = async { fetchChannels() } println(“Deferred !-> ${result.await()}”)

Slide 31

Slide 31 text

Deferred Communicate Deferred is a non-blocking cancelable future
 val result = CompletableDeferred() launch(Dispatchers.IO) { result.complete(slowFetch()) } println(“Deferred !-> ${result.await()}”)

Slide 32

Slide 32 text

Deferred Mutex Communicate Mutex is Kotlins Mutual Exclusion
 val mutex = Mutex() suspend fun critical() { mutex.withLock { println(“Start $thread”) delay(100) println(“Stop $thread”) } } repeat(2) { launch(Dispatchers.Default) { critical() } }

Slide 33

Slide 33 text

Deferred Mutex Channel Communicate Channels are synchronization primitives for streams
 suspend fun compete(name:String): String { delay(nextLong(5000)) return name } val race = Channel() launch(…) { race.send(compete("Bob")) } launch(…) { race.send(compete(“Emilie")) } launch(…) { race.send(compete(“Charlie")) } launch(…) { race.send(compete(“Filippa")) } launch(Dispatchers.Default) { repeat(4) { println(“Name: ${race.receive()}") } race.close() }

Slide 34

Slide 34 text

Deferred Mutex Channel Communicate Channels are synchronization primitives for streams
 val ch: Channel = produce { repeat(30) { send(it) } } repeat(3) { id !-> launch(Dispatchers.Default) { for(msg in ch) { println(“$id !-> $msg”) } } }

Slide 35

Slide 35 text

Deferred Mutex Channel Communicate Channels are synchronization primitives for streams
 Channel(7) !// BUFFERED Channel(Channel.UNLIMITED) Channel(Channel.CONFLATED) Channel(Channel.RENDEZVOUS)

Slide 36

Slide 36 text

Deferred Mutex Channel Flow Communicate Kotlins take on reactive streams
 val example = flow { for(i in 1!..10) { println(“Flow on !-> ${thread()}”) emit(i) } } !// on main thread example.filter { it !>= 5 } .map { it * 2 } .collect { println(“Collect on !-> ${thread()}”) }

Slide 37

Slide 37 text

Deferred Mutex Channel Flow Communicate Kotlins take on reactive streams
 val example = flow { for(i in 1!..10) { println(“Flow on !-> ${thread()}”) emit(i) } }.flowOn(Dispatchers.Default) !// on main thread example.filter { it !>= 5 } .map { it * 2 } .collect { println(“Collect on !-> ${thread()}”) }

Slide 38

Slide 38 text

Deferred Mutex Channel Flow Communicate Kotlins take on reactive streams
 val example = flow { for(i in 1!..10) { println(“Flow on !-> ${thread()}”) emit(i) } } !// on main thread example.filter { it !>= 5 } .map { it * 2 } .flowOn(Dispatchers.Default) .collect { println(“Collect on !-> ${thread()}”) }

Slide 39

Slide 39 text

Deferred Mutex Channel Flow Communicate Kotlins take on reactive streams
 val example = flow { for(i in 1!..10) { println(“Flow on !-> ${thread()}”) emit(i) } } !// on main thread example.filter { it !>= 5 } .flowOn(Dispatchers.IO) .map { it * 2 } .flowOn(Dispatchers.Default) .collect { println(“Collect on !-> ${thread()}”) }

Slide 40

Slide 40 text

Thank you!

Slide 41

Slide 41 text

Questions? Bob Dahlberg [email protected] medium.com/dahlbergbob @mr_bob This Presentation tiny.cc/fosdem-bob speakerdeck.com/bobdahlberg