Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Actors - No Drama Concurrency

Kotlin Actors - No Drama Concurrency

Sam Edwards

July 14, 2020
Tweet

More Decks by Sam Edwards

Other Decks in Programming

Transcript

  1. 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.
  2. 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.
  3. 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.
  4. 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)
 }
  5. 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
  6. 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") }
  7. Actors Processes incoming Messages/Intentions sealed class Intention { class FindByLabel(

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

    val label: String, val deferred: CompletableDeferred<ItemWithQuantity?> ) : Intention() class Upsert(val itemWithQuantity: ItemWithQuantity) : Intention() class Remove(val itemWithQuantity: ItemWithQuantity) : Intention() object Empty : Intention() }
  9. Actors are: Processes incoming Messages/Intentions Return values with CompletableDeferred override

    suspend fun findByLabel(label: String): ItemWithQuantity? { val deferred = CompletableDeferred<ItemWithQuantity?>() actor.send( Intention.FindByLabel( label = label, deferred = deferred ) ) return deferred.await() }
  10. Actors are: Processes incoming Messages/Intentions private val actor = scope.actor<Intention>

    { val itemsInCart: MutableMap<String, ItemWithQuantity> = 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 } } }
  11. Actors are: Backed by a Channel public fun <E> CoroutineScope.actor(

    context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, // todo: Maybe Channel.DEFAULT here? start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend ActorScope<E>.() -> Unit ): SendChannel<E> { val newContext = newCoroutineContext(context) val channel = Channel<E>(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 }
  12. Actors are: Concurrent • It’s a single coroutine, processing messages

    sequentially • Incoming messages are queued and processed
  13. 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.
  14. 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.
  15. 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.
  16. 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.
  17. 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.
  18. 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.
  19. 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.
  20. 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.