Slide 1

Slide 1 text

Sam Edwards @HandstandSam Actors No Drama Concurrency

Slide 2

Slide 2 text

Concurrency?

Slide 3

Slide 3 text

Concurrency is the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome. This allows for parallel execution of the concurrent units, which can significantly improve overall speed of the execution in multi-processor and multi-core systems.

Slide 4

Slide 4 text

Concurrency is: • the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome. This allows for: • parallel execution of the concurrent units, which can significantly improve overall speed of the execution in multi-processor and multi-core systems.

Slide 5

Slide 5 text

Concurrency is: • the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome. This allows for: • parallel execution of the concurrent units, which can significantly improve overall speed of the execution in multi-processor and multi-core systems.

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Coroutines

Slide 11

Slide 11 text

Kotlin Coroutines Explained in one slide • A function with a suspend keyword signifies it must run in a Coroutine
 
 suspend fun doNetworkRequest() : Result {
 // Network Request Occurs
 } • suspend functions must be executed within a CoroutineContext and Once inside a coroutine, code executes sequentially
 
 CoroutineContext(Dispatchers.Default).launch{
 val result = doNetworkRequest()
 processResult(result)
 }

Slide 12

Slide 12 text

“Essentially, coroutines are light-weight threads. They are launched in a context of some CoroutineScope.”

Slide 13

Slide 13 text

“Essentially, coroutines are light-weight threads. They are launched in a context of some CoroutineScope.”

Slide 14

Slide 14 text

Concurrent Code with Kotlin Coroutines? https://kotlinlang.org/docs/reference/coroutines/shared-mutable-state-and-concurrency.html • Mutex • Thread Safe Data Structures - AtomicInteger(), etc (Blocks thread) • Thread Confinement - Main Thread!!! • Actors - Executes in it’s own Coroutine

Slide 15

Slide 15 text

Mutex https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.sync/-mutex/ val mutex = Mutex() var counter = 0 fun main() = runBlocking { withContext(Dispatchers.Default) { massiveRun { // protect each increment with lock mutex.withLock { counter++ } } } println("Counter = $counter") }

Slide 16

Slide 16 text

Thread-Safe Data Structures https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-atomic-int/ • val atomicInt = AtomicInt(0) • atomicInt.increment() • atomicInt.decrement() • atomicInt.value

Slide 17

Slide 17 text

Thread Confinement https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-atomic-int/ • CoroutineContext(Dispatchers.Main).launch {} • Executes suspended code on the Main thread • runBlocking {} • Executes suspended code on the current thread

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Actors

Slide 20

Slide 20 text

Actors are: • A Single Coroutine • Processes incoming Messages • Backed by a Channel • Concurrent

Slide 21

Slide 21 text

Actors are: A Single Coroutine Actor Coroutine Process Messages Messages via Channel Messages via Channel for() loop

Slide 22

Slide 22 text

Actors Processes incoming Messages/Intentions sealed class Intention { class FindByLabel( val label: String, val deferred: CompletableDeferred ) : Intention() class Upsert(val itemWithQuantity: ItemWithQuantity) : Intention() class Remove(val itemWithQuantity: ItemWithQuantity) : Intention() object Empty : Intention() }

Slide 23

Slide 23 text

Actors Processes incoming Messages/Intentions sealed class Intention { class FindByLabel( val label: String, val deferred: CompletableDeferred ) : Intention() class Upsert(val itemWithQuantity: ItemWithQuantity) : Intention() class Remove(val itemWithQuantity: ItemWithQuantity) : Intention() object Empty : Intention() }

Slide 24

Slide 24 text

Actors are: Processes incoming Messages/Intentions Return values with CompletableDeferred override suspend fun findByLabel(label: String): ItemWithQuantity? { val deferred = CompletableDeferred() actor.send( Intention.FindByLabel( label = label, deferred = deferred ) ) return deferred.await() }

Slide 25

Slide 25 text

Actors are: Processes incoming Messages/Intentions private val actor = scope.actor { val itemsInCart: MutableMap = mutableMapOf() for (intention in channel) { when (intention) { is Intention.FindByLabel -> { intention.deferred.complete(itemsInCart[intention.label]) } is Intention.Upsert -> { itemsInCart[intention.itemWithQuantity.item.label] = intention.itemWithQuantity } is Intention.Remove -> itemsInCart.remove(intention.itemWithQuantity.item.label) is Intention.Empty -> itemsInCart.clear() } val sortedItems = itemsInCart.values.toList() .sortedBy { it.item.label } if (itemsChannel.value != sortedItems) { itemsChannel.send(sortedItems) } else { // No change detected, don't emit } } }

Slide 26

Slide 26 text

Actors are: Backed by a Channel public fun CoroutineScope.actor( context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, // todo: Maybe Channel.DEFAULT here? start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend ActorScope.() -> Unit ): SendChannel { val newContext = newCoroutineContext(context) val channel = Channel(capacity) val coroutine = if (start.isLazy) LazyActorCoroutine(newContext, channel, block) else ActorCoroutine(newContext, channel, active = true) if (onCompletion != null) coroutine.invokeOnCompletion(handler = onCompletion) coroutine.start(start, coroutine, block) return coroutine }

Slide 27

Slide 27 text

Actors are: Concurrent • It’s a single coroutine, processing messages sequentially • Incoming messages are queued and processed

Slide 28

Slide 28 text

OMG! @ObsoleteCoroutinesApi

Slide 29

Slide 29 text

kotlinx.coroutines - Actors https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/actor.html

Slide 30

Slide 30 text

@ObsoleteCoroutinesApi


Slide 31

Slide 31 text

kotlinx.coroutines - ObsoleteCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/ annotation class ObsoleteCoroutinesApi (source) Marks declarations that are obsolete in coroutines API, which means that the design of the corresponding declarations has serious known flaws and they will be redesigned in the future. Roughly speaking, these declarations will be deprecated in the future but there is no replacement for them yet, so they cannot be deprecated right away.

Slide 32

Slide 32 text

kotlinx.coroutines - ObsoleteCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/ annotation class ObsoleteCoroutinesApi (source) Marks declarations that are obsolete in coroutines API, which means that the design of the corresponding declarations has serious known flaws and they will be redesigned in the future. Roughly speaking, these declarations will be deprecated in the future but there is no replacement for them yet, so they cannot be deprecated right away.

Slide 33

Slide 33 text

kotlinx.coroutines - ObsoleteCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/ annotation class ObsoleteCoroutinesApi (source) Marks declarations that are obsolete in coroutines API, which means that the design of the corresponding declarations has serious known flaws and they will be redesigned in the future. Roughly speaking, these declarations will be deprecated in the future but there is no replacement for them yet, so they cannot be deprecated right away.

Slide 34

Slide 34 text

kotlinx.coroutines - ObsoleteCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-obsolete-coroutines-api/ annotation class ObsoleteCoroutinesApi (source) Marks declarations that are obsolete in coroutines API, which means that the design of the corresponding declarations has serious known flaws and they will be redesigned in the future. Roughly speaking, these declarations will be deprecated in the future but there is no replacement for them yet, so they cannot be deprecated right away.

Slide 35

Slide 35 text

kotlinx.coroutines - Writing complex actors https://github.com/Kotlin/kotlinx.coroutines/issues/87

Slide 36

Slide 36 text

kotlinx.coroutines - Writing complex actors https://github.com/Kotlin/kotlinx.coroutines/issues/87

Slide 37

Slide 37 text

Are Actors Going Away? Kotlin GDE AMA with Roman Elizarov • Actors are not deprecated, and they will remain. • Original Actors were designed pre-structured concurrency. They won’t drop simple actors. • The replacements will support the simple use case just as well.

Slide 38

Slide 38 text

What About StateFlow? I thought you’d never ask…

Slide 39

Slide 39 text

StateFlow?
 $

Slide 40

Slide 40 text

StateFlow https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/index.html • A Flow that represents a read-only state with a single updatable data value that emits updates to the value to its collectors. The current value can be retrieved via value property. The flow of future updates to the value can be observed by collecting values from this flow.

Slide 41

Slide 41 text

MutableStateFlow https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-state-flow/index.html A mutable StateFlow that provides a setter for value.

Slide 42

Slide 42 text

Actor + StateFlow Example https://github.com/handstandsam/ShoppingApp/pull/29

Slide 43

Slide 43 text

OMG! @ExperimentalCoroutinesApi

Slide 44

Slide 44 text

@ExperimentalCoroutinesApi


Slide 45

Slide 45 text

kotlinx.coroutines - ExperimentalCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-experimental-coroutines-api/ annotation class ExperimentalCoroutinesApi (source) Marks declarations that are still experimental in coroutines API, which means that the design of the corresponding declarations has open issues which may (or may not) lead to their changes in the future. Roughly speaking, there is a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change in some way that may break some code.

Slide 46

Slide 46 text

kotlinx.coroutines - ExperimentalCoroutinesApi https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-experimental-coroutines-api/ annotation class ExperimentalCoroutinesApi (source) Marks declarations that are still experimental in coroutines API, which means that the design of the corresponding declarations has open issues which may (or may not) lead to their changes in the future. Roughly speaking, there is a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change in some way that may break some code.

Slide 47

Slide 47 text

Actor and StateFlow

Slide 48

Slide 48 text

Actors and StateFlow •Complimentary •Actor (Thread Safety) •StateFlow (Data Container)

Slide 49

Slide 49 text

Thank You! Sam Edwards - @HandstandSam