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

Dissecting Coroutines Library

B3f560d34c14a9113e5024bc34ac26a0?s=47 Mohit S
November 28, 2020

Dissecting Coroutines Library

B3f560d34c14a9113e5024bc34ac26a0?s=128

Mohit S

November 28, 2020
Tweet

Transcript

  1. Mohit Sarveiya Dissecting Coroutines Library @heyitsmohit

  2. Dissecting Coroutines Library • Context • Channels • Flows •

    Shared Mutable State
  3. Dissecting Coroutines Library • Implementation • Use cases

  4. Context

  5. val scope = CoroutineScope(Dispatchers.IO) scope.launch { }

  6. val scope = CoroutineScope(Dispatchers.IO) fun CoroutineScope(context: CoroutineContext)

  7. interface CoroutineContext { interface Key<E : Element> interface Element }

  8. interface CoroutineContext { interface Key<E : Element> interface Element }

  9. interface CoroutineContext { operator fun get(key: Key<E>): E? operator fun

    plus(context: CoroutineContext): CoroutineContext }
  10. interface CoroutineContext { operator fun get(key: Key<E>): E? operator fun

    plus(context: CoroutineContext) }
  11. Context Elements • Job • Coroutine Name • Dispatcher

  12. val scope = CoroutineScope( CoroutineName("My Coroutine") + Dispatchers.IO )

  13. val scope = CoroutineScope( CoroutineName("My Coroutine") + Dispatchers.IO ) operator

    fun plus(context: CoroutineContext)
  14. val scope = CoroutineScope( CoroutineName("My Coroutine") + Dispatchers.IO ) scope.coroutineContext[CoroutineName]

  15. val scope = CoroutineScope( CoroutineName("My Coroutine") + Dispatchers.IO ) scope.coroutineContext[CoroutineName]

    / / CoroutineName(My Coroutine)
  16. val scope = CoroutineScope( CoroutineName("My Coroutine") + Dispatchers.IO ) scope.coroutineContext[ContinuationInterceptor]

  17. val job = Job() val scope = CoroutineScope( CoroutineName("My Coroutine")

    + job + Dispatchers.IO )
  18. val job = Job() val scope = CoroutineScope( CoroutineName("My Coroutine")

    + job + Dispatchers.IO )
  19. val job = Job() val scope = CoroutineScope( CoroutineName("My Coroutine")

    + job + Dispatchers.IO ) scope.coroutineContext[Job] / / JobImpl{Active}
  20. Custom Context Use Cases • Dispatcher Provider (Dispatch) • Thread

    Local (krotoPlus) • Database Transactions (Room)
  21. RBusarow/Dispatch Code ! Issues Pull Requests Dispatch Bazel Build passing

    Gradle Build passing Utilities for kotlinx.coroutines which make them type-safe, easier to test, and more expressive.
  22. Scopes • IOScope • DefaultScope • UnDispatchedScope

  23. class DefaultDispatcherProvider { val default: CoroutineDispatcher = Dispatchers.Default val io:

    CoroutineDispatcher = Dispatchers.IO val main: CoroutineDispatcher = Dispatchers.Main }
  24. interface DispatcherProvider : CoroutineContext.Element { override val key: CoroutineContext.Key <

    * > get() = Key companion object Key : CoroutineContext.Key<DispatcherProvider> }
  25. fun IOCoroutineScope(dispatcherProvider = DefaultDispatcherProvider()) { override val coroutineContext = job

    + dispatcherProvider.io + dispatcherProvider }
  26. Resources • Custom Coroutine Context Use Cases • Dispatch

  27. Channels

  28. Coroutine Coroutine Channel

  29. Coroutine Coroutine Data Channel

  30. interface Channel<E> { suspend fun send(element: E) suspend fun receive():

    E } Channel
  31. Channel Types • Rendezvous • Buffered • Unlimited

  32. fun <E> Channel(capacity: Int = RENDEZVOUS) = when (capacity) {

    RENDEZVOUS - > RendezvousChannel() UNLIMITED - > LinkedListChannel() CONFLATED - > ConflatedChannel() BUFFERED - > ArrayChannel(CHANNEL_DEFAULT_CAPACITY) else - > ArrayChannel(capacity) }
  33. Channel Types • Rendezvous • Buffered • Unlimited

  34. runBlocking { 
 val channel = Channel<Int>() launch { channel.send(1)

    } val num = channel.receive() }
  35. runBlocking { 
 val channel = Channel<Int>() launch { channel.send(1)

    } val num = channel.receive() }
  36. runBlocking { 
 val channel = Channel<Int>() launch { channel.send(1)

    } val num = channel.receive() }
  37. runBlocking { 
 val channel = Channel<Int>() launch { channel.send(1)

    } val num = channel.receive() } SUSPEND
  38. runBlocking { 
 val channel = Channel<Int>() launch { channel.send(1)

    } val num = channel.receive() }
  39. Channel Types • Rendezvous • Buffered • Unlimited

  40. runBlocking { 
 val channel = Channel<Int>(10) launch { channel.send(1)

    } val num = channel.receive() }
  41. runBlocking { 
 val channel = Channel<Int>(10) launch { channel.send(1)

    channel.send(2) channel.send(3) } }
  42. Channel Types • Rendezvous • Buffered • Unlimited

  43. runBlocking { 
 val channel = Channel<Int>(Channel.UNLIMITED) launch { channel.send(1)

    channel.send(2) channel.send(3) } }
  44. runBlocking { 
 val channel = Channel<Int>(Channel.UNLIMITED) launch { channel.send(1)

    channel.send(2) channel.send(3) } }
  45. Channel Types • Rendezvous • Buffered • Unlimited

  46. Papers

  47. Channel State • Queue • Optional Buffer

  48. Channel Queue States • Empty • Send Queued • Send

    Buffered • Closed
  49. Channel Queue States Lock Free Linked List Node Empty Queue

    Send Buffered Send Queued Closed
  50. val channel = Channel<Int>() Queue Empty Queue

  51. val channel = Channel<Int>() channel.send(1)

  52. class SendElement( val data: Any?, val cont: CancellableContinuation<Unit> ) :

    LockFreeLinkedListNode()
  53. val channel = Channel<Int>() channel.send(1) Queue Send Element(1)

  54. val channel = Channel<Int>() channel.send(1) channel.receive() Queue Empty Queue

  55. val channel = Channel<Int>() channel.send(1) println(channel)

  56. val channel = Channel<Int>() channel.send(1) println(channel) / / RendezvousChannel{SendQueued}

  57. class AbstractSendChannel { fun toString() = {$queueDebugStateString}$bufferDebugString” } Query Channel

    State
  58. class AbstractSendChannel { fun toString() = {$queueDebugStateString}$bufferDebugString” } Query Channel

    State
  59. $queueDebugStateString get() { 
 when (head) { 
 is Closed

    < * > - > head.toString() 
 is Receive < * > - > "ReceiveQueued" 
 is Send - > "SendQueued" else - > "UNEXPECTED:$head" } } Query Channel State
  60. $queueDebugStateString get() { 
 when (head) { 
 is Closed

    < * > - > head.toString() 
 is Receive < * > - > "ReceiveQueued" 
 is Send - > "SendQueued" else - > "UNEXPECTED:$head" } } Query Channel State
  61. $queueDebugStateString get() { 
 when (head) { 
 is Closed

    < * > - > head.toString() 
 is Receive < * > - > "ReceiveQueued" 
 is Send - > "SendQueued" else - > "UNEXPECTED:$head" } } Query Channel State
  62. $queueDebugStateString get() { 
 when (head) { 
 is Closed

    < * > - > head.toString() 
 is Receive < * > - > "ReceiveQueued" 
 is Send - > "SendQueued" else - > "UNEXPECTED:$head" } } Query Channel State
  63. $queueDebugStateString get() { 
 when (head) { 
 is Closed

    < * > - > head.toString() 
 is Receive < * > - > "ReceiveQueued" 
 is Send - > "SendQueued" else - > "UNEXPECTED:$head" } } Query Channel State
  64. val channel = Channel<Int>() channel.send(1) println(channel) / / RendezvousChannel{SendQueued} Query

    Channel State
  65. runBlocking { 
 val channel = Channel<Int>(10) launch { channel.send(1)

    channel.send(2) channel.send(3) } }
  66. runBlocking { 
 val channel = Channel<Int>(10) launch { channel.send(1)

    channel.send(2) channel.send(3) println(channel) } }
  67. runBlocking { 
 val channel = Channel<Int>(10) launch { channel.send(1)

    channel.send(2) channel.send(3) println(channel) } } / / BufferedChannel{SendQueued}{3}
  68. fun CoroutineScope.producer(): ReceiveChannel<Int> = 
 produce { for (i in

    1 . . 5) { send(i) } }
  69. fun CoroutineScope.producer(): ReceiveChannel<Int> = 
 produce { for (i in

    1 . . 5) { send(i) } }
  70. fun CoroutineScope.producer(): ReceiveChannel<Int> = 
 produce { for (i in

    1 . . 5) { send(i) } close() }
  71. runBlocking { 
 val channel: ReceiveChannel<Int> = producer() for (num

    in channel) { calculate(num) } }
  72. runBlocking { 
 val channel: ReceiveChannel<Int> = producer() for (num

    in channel) { } }
  73. interface ChannelIterator<out E> { suspend fun hasNextSuspend(): E fun next():

    E } Channel Iterator
  74. Coroutine A EmptyQueue Channel Queue Coroutine B

  75. Coroutine A SendElement(1) Channel Queue Coroutine B 1

  76. Coroutine A SendElement(1) Channel Queue Coroutine B 1 hasNext()

  77. Coroutine A SendElement(1) Channel Queue Coroutine B 1 next()

  78. Coroutine A SendElement(1) Channel Queue Coroutine B 1 next()

  79. Coroutine A SendElement(1) Channel Queue Coroutine B 1 next() 2

    3
  80. Coroutine A SendElement(1) Channel Queue Coroutine B 1 2 3

    X
  81. runBlocking { 
 val channel: ReceiveChannel<Int> = producer() for (num

    in channel) { } }
  82. Papers

  83. Channels • Implementation • Use cases

  84. marcoferrer/kroto-plus Code ! Issues Pull Requests Kroto-Plus+ - An RPC

    library and framework Bazel Build passing Gradle Build passing A Kotlin/JVM implementation of gRPC: A high performance, open source, general RPC framework that puts mobile and HTTP/2 first.
  85. Server gRPC

  86. Server gRPC service

  87. Server(Go) gRPC service Client(Java) Client(Python) Client(Javascript) service service service

  88. Server(Go) gRPC service Client(Java) Client(Python) Client(Javascript)

  89. Server(Go) gRPC service Client(Java) Client(Python) Client(Javascript) call call call

  90. Server(Go) gRPC service Client(Java) Client(Python) Client(Javascript) call call call HTTP

    2
  91. Channels with gRPC Client Server Scope (Dispatcher) Request Send Channel

    Receive Channel
  92. Client Server Scope (Dispatcher) Request Send Channel Receive Channel Channels

    with gRPC
  93. Client Server Scope (Dispatcher) Response Send Channel Receive Channel Channels

    with gRPC
  94. Resources • Lock-free algorithms for Kotln Corotuines (Part 1) •

    Lock-free algorithms for Kotln Corotuines (Part 2) • gRPC with Kotlin Coroutines
  95. Flows

  96. Coroutine Coroutine Flow

  97. Coroutine Coroutine Flow

  98. val flow = flowOf(1,2,3)

  99. val flow = flowOf(1,2,3) flow.collect { println(it) }

  100. val flow = flow { emit(1) delay(2000) emit(1) }

  101. flow .filter { } .map { } .combine(flow2) { }

  102. flow .filter { } .map { } .combine(flow2) { }

    .flowOn(Dispatchers.IO)
  103. flow.collect { }

  104. flow.launchIn(scope)

  105. fun Flow<T>.launchIn(scope: CoroutineScope): Job = scope.launch { collect() }

  106. val value = flow.single()

  107. Bridge to Flow

  108. apollographql/apollo-android Code ! Issues Pull Requests Apollo Android Bazel Build

    passing Gradle Build passing Apollo Android is a GraphQL client that generates Java and Kotlin models from GraphQL queries.
  109. val client = ApolloClient.builder() .serverUrl(“url") .build()

  110. client.query(query).enqueue( object : ApolloCall.Callback() { override fun onResponse(response: Response) {

    } override fun onFailure(e: ApolloException) { } override fun onStatusEvent(event: ApolloCall.StatusEvent) { } })
  111. client.query(query).enqueue( object : ApolloCall.Callback() { override fun onResponse(response: Response) {

    } override fun onFailure(e: ApolloException) { } override fun onStatusEvent(event: ApolloCall.StatusEvent) { } })
  112. Callback Flow • Coroutine on Produce Scope • Provides a

    channel to send
  113. callbackFlow { }

  114. callbackFlow { enqueue( object : ApolloCall.Callback<T>() { override fun onResponse(response:

    Response<T>) { offer(response) } override fun onFailure(e: ApolloException) { close(e) } override fun onStatusEvent(event: ApolloCall.StatusEvent) { if (event = = ApolloCall.StatusEvent.COMPLETED) { close() } }
  115. callbackFlow { enqueue( object : ApolloCall.Callback<T>() { override fun onResponse(response:

    Response<T>) { offer(response) } override fun onFailure(e: ApolloException) { close(e) } override fun onStatusEvent(event: ApolloCall.StatusEvent) { if (event = = ApolloCall.StatusEvent.COMPLETED) { close() } }
  116. callbackFlow { enqueue( object : ApolloCall.Callback<T>() { override fun onResponse(response:

    Response<T>) { offer(response) } override fun onFailure(e: ApolloException) { close(e) } override fun onStatusEvent(event: ApolloCall.StatusEvent) { if (event = = ApolloCall.StatusEvent.COMPLETED) { close() } }
  117. callbackFlow { enqueue( object : ApolloCall.Callback<T>() { override fun onResponse(response:

    Response<T>) { offer(response) } override fun onFailure(e: ApolloException) { close(e) } override fun onStatusEvent(event: ApolloCall.StatusEvent) { if (event = = ApolloCall.StatusEvent.COMPLETED) { close() } }
  118. callbackFlow { 
 enqueue( . . . ) 
 awaitClose

    { cancel() } }
  119. fun <T> ApolloCall<T>.toFlow() { callbackFlow { 
 enqueue( . .

    . ) 
 awaitClose { this@toFlow.cancel() } } }
  120. val flow = client.query(query).toFlow()

  121. Combine

  122. 1 2 3 1s 1s

  123. 1 2 3 1s 1s val numbersFlow = flowOf(1,2,3) .onEach

    { delay(1000) }
  124. A B C 2s 2s

  125. A B C 2s 2s val lettersFlow = flowOf("A", “B","C")

    .onEach { delay(2000) }
  126. 1 2 3 A B C 1s 1s 2s 2s

    Combine
  127. numbersFlow.combine(lettersFlow) { number, letter - > }

  128. numbersFlow.combine(lettersFlow) { number, letter - > "$number$letter" }

  129. 1 2 3 A B C 1s 1s 2s 2s

    1A 2A 3C 3A 3B
  130. numbersFlow.combine(lettersFlow) { number, letter - > "$number$letter" }.collect { println(it)

    }
  131. numbersFlow.combine(lettersFlow) { number, letter - > "$number$letter" }.collect { print(it)

    } HelloWorld.kt 1A 2A 3A 3B 3C
  132. 1 2 3 A B C 1s 1s 2s 2s

    How did combine work?
  133. 1.4.x 1.3.x Zip, Combine Implementation Evolution Selectors New Version

  134. Selectors

  135. Send Send Channel A Channel B

  136. Send Send Channel A Channel B

  137. Send Send Channel A Channel B Receive

  138. Send Channel A Channel B Send Receive

  139. Channel B Send Receive Channel A Send Receive Read simultaneously

    from both channels?
  140. fun CoroutineScope.hello() = produce { while (true) { delay(300) send("Hello")

    } } Send Hello
  141. fun CoroutineScope.world() = produce { while (true) { delay(500) send("World!")

    } } Send World!
  142. val receiveChannel = hello() 
 fun CoroutineScope.hello() = produce {

    while (true) { delay(300) send("Hello") } } Send Hello
  143. val receiveChannel = hello() receiveChannel.receive() 
 fun CoroutineScope.hello() = produce

    { while (true) { delay(300) send("Hello") } } Send Receive
  144. Channel B Send Receive Channel A Send Receive Read simultaneously

    from both channels?
  145. suspend fun selectHelloWorld(channelA, channelB) { }

  146. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { } } Selector

  147. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { } } Return

  148. interface ReceiveChannel { onReceive: SelectClause1 val onReceiveOrNull: SelectClause1 onReceiveOrClosed: SelectClause1

    }
  149. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceive { value

    - > } } }
  150. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceive { value

    - > } channelB.onReceive { value - > } } }
  151. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceive { value

    - > println(value) } channelB.onReceive { value - > println(value) } } }
  152. val channelA = hello() val channelB = world() selectHelloWorld(channelA, channelB)

  153. fun CoroutineScope.hello() = produce { while (true) { delay(300) send("Hello")

    } } selectHelloWorld(channelA, channelB)
  154. fun CoroutineScope.hello() = produce { while (true) { delay(300) send("Hello")

    } } selectHelloWorld(channelA, channelB)
  155. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceive { value

    - > println(value) } channelB.onReceive { value - > println(value) } } } / / Hello
  156. val channelA = hello() val channelB = world() selectHelloWorld(channelA, channelB)

    selectHelloWorld(channelA, channelB)
  157. fun CoroutineScope.world() = produce { while (true) { delay(500) send("World!")

    } } selectHelloWorld(channelA, channelB)
  158. fun CoroutineScope.world() = produce { while (true) { delay(500) send("World!")

    } } selectHelloWorld(channelA, channelB)
  159. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceive { value

    - > println(value) } channelB.onReceive { value - > println(value) } } } / / World!
  160. val channelA = hello() val channelB = world() Close

  161. interface ReceiveChannel { onReceive: SelectClause1 val onReceiveOrNull: SelectClause1 onReceiveOrClosed: SelectClause1

    }
  162. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceiveOrNull { value

    - > } channelB.onReceiveOrNull { value - > } } }
  163. suspend fun selectHelloWorld(channelA, channelB) { select<Unit> { channelA.onReceiveOrNull { value

    - > } channelB.onReceiveOrNull { value - > } } } Null when channelA closed
  164. Channel B Send Receive Channel A Send Receive Read simultaneously

    from both channels Selectors
  165. 1 2 3 A B C 1s 1s 2s 2s

    Combine
  166. 1 2 3 Send Channel A

  167. 1 2 3 Send Channel A

  168. A B C Send Channel B

  169. A B C Send Channel B

  170. Send Channel B Send Channel A Selector A 1

  171. Send Channel B Send Channel A Selector A 1

  172. Send Channel B Send Channel A Selector A 1 Transform

  173. Send Channel B Send Channel A Selector A 1

  174. 1 2 3 A B C 1A 2A

  175. Send Channel B Send Channel A Selector A

  176. 1 2 3 A B C 1A 2A

  177. Send Channel B Send Channel A Selector A

  178. Send Channel B Send Channel A Selector A 2

  179. Send Channel B Send Channel A Selector A 2

  180. Send Channel B Send Channel A Selector A 2

  181. suspend fun combine( first: Flow<T1>, second: Flow<T2>, transform: suspend FlowCollector<R>.(a:

    T1, b: T2) - > Unit ) { }
  182. suspend fun combine( first: Flow<T1>, second: Flow<T2>, transform: suspend FlowCollector<R>.(a:

    T1, b: T2) - > Unit ) { }
  183. suspend fun combine( . . . ) { val firstChannel

    = createChannel(firstFlow) val secondChannel = createChannel(secondFlow) }
  184. suspend fun combine( . . . ) { val firstChannel

    = createChannel(firstFlow) val secondChannel = createChannel(secondFlow) var firstValue: Any? = null var secondValue: Any? = null }
  185. suspend fun combine( . . . ) { val firstChannel

    = createChannel(firstFlow) val secondChannel = createChannel(secondFlow) var firstValue: Any? = null var secondValue: Any? = null var firstIsClosed = false var secondIsClosed = false }
  186. suspend fun combine( . . . ) { while (!firstIsClosed

    | | !secondIsClosed) { } }
  187. suspend fun combine( . . . ) { while (!firstIsClosed

    | | !secondIsClosed) { select<Unit> { } } }
  188. select<Unit> { channelA.onReceive { value - > firstValue = value

    if (secondValue ! = = null) { transform( . . . ) } } channelB.onReceive { value - > secondValue = value if (secondValue ! = = null) { transform( . . . ) } }
  189. select<Unit> { channelA.onReceive { value - > firstValue = value

    if (secondValue ! = = null) { transform( . . . ) } } channelB.onReceive { value - > secondValue = value if (firstValue ! = = null) { transform( . . . ) } }
  190. 1 2 3 A B C 1s 1s 2s 2s

    Combine
  191. Shared Flow

  192. val channel = ConflatedBroadcastChannel(10)

  193. val channel = ConflatedBroadcastChannel(10) channel.send(1) channel.send(2) / / Conflate previously

    sent
  194. val channel = ConflatedBroadcastChannel(10) channel.send(1) channel.send(2) / / Conflate previously

    sent channel.close()
  195. Shared Flow • Mutable State Flow • Mutable Shared Flow

  196. View View Model State

  197. class MyViewModel(): ViewModel() { } Jetpack View Model

  198. val ViewModel.viewModelScope: CoroutineScope get() { return setTagIfAbsent(JOB_KEY, CloseableCoroutineScope( 
 SupervisorJob()

    + Dispatchers.Main.immediate) 
 ) }
  199. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) } State

    Flow
  200. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.value = state } .launchIn(viewModelScope) } }
  201. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.value = state } .launchIn(viewModelScope) } }
  202. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.value = state } .launchIn(viewModelScope) } }
  203. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) fun updateState()

    { flowOfData .map { mapToState(data) } .collect { state - > 
 states.value = state } / / logic after collect will run after it finishes } } Suspending
  204. class MyViewModel(): ViewModel() { val states = MutableStateFlow(State()) fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.value = state } .launchIn(viewModelScope) } }
  205. class MyViewModel(): ViewModel() { val states = MutableSharedFlow() fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.value = state } .launchIn(viewModelScope) } }
  206. class MyViewModel(): ViewModel() { val states = MutableSharedFlow() fun updateState()

    { flowOfData .map { mapToState(data) } .onEach { state - > states.emit(data) } .launchIn(viewModelScope) } }
  207. Mutable State

  208. State

  209. State Coroutine Coroutine Coroutine

  210. State Coroutine Coroutine Coroutine

  211. Mutable State • Mutex • Actor

  212. var counter = 0 suspend fun CoroutineScope.updateState() { }

  213. var counter = 0 suspend fun CoroutineScope.updateState() { val jobs

    = List(100) { launch { } } }
  214. var counter = 0 suspend fun CoroutineScope.updateState() { val jobs

    = List(100) { launch { repeat(1000) { counter + + } } } }
  215. var counter = 0 updateState()

  216. var counter = 0 updateState() println(counter) / / 71906

  217. var counter = 0 updateState() println(counter) / / 56467

  218. Mutex

  219. public interface Mutex { val isLocked: Boolean suspend fun lock()

    fun unlock() }
  220. var counter = 0 suspend fun CoroutineScope.updateState() { val jobs

    = List(100) { launch { repeat(1000) { counter + + } } } }
  221. var mutext = Mutex() var counter = 0 suspend fun

    CoroutineScope.updateState() { val jobs = List(100) { launch { repeat(1000) { counter + + } } } }
  222. var mutext = Mutex() var counter = 0 suspend fun

    CoroutineScope.updateState() { 
 val jobs = List(100) { launch { repeat(1000) { mutext.lock() counter + + } } } }
  223. var mutext = Mutex() var counter = 0 suspend fun

    CoroutineScope.updateState() { 
 val jobs = List(100) { launch { repeat(1000) { mutext.lock() try { counter + + } finally { mutext.unlock() } }
  224. var mutext = Mutex() var counter = 0 suspend fun

    CoroutineScope.updateState() { List(100) { launch { repeat(1000) { mutext.lock() try { counter + + } finally { mutext.unlock() } }
  225. fun <T> Mutex.withLock(owner, action: () - > T): T {

    lock(owner) try { return action() } finally { unlock(owner) } }
  226. var mutext = Mutex() var counter = 0 suspend fun

    CoroutineScope.updateState() { List(100) { launch { repeat(1000) { mutext.withLock { counter + + } 
 } } }
  227. Actor

  228. Actor

  229. Actor State

  230. Mailbox State Actor

  231. Actor Mailbox Coroutine State

  232. State Actor Mailbox Coroutine Event

  233. State Actor Mailbox Coroutine Event

  234. State Actor Mailbox Coroutine Event

  235. sealed class CounterEvents { }

  236. sealed class CounterEvents { object IncCounter : CounterEvents() }

  237. sealed class CounterEvents { object IncCounter : CounterEvents() class GetCounter(

    val response: CompletableDeferred<Int> ): CounterEvents() }
  238. fun CoroutineScope.counterActor() = actor<CounterEvents> { }

  239. fun CoroutineScope.counterActor() = actor<CounterEvents> { var counter = 0 }

  240. fun CoroutineScope.counterActor() = actor<CounterEvents> { var counter = 0 for

    (event in channel) { } }
  241. fun CoroutineScope.counterActor() = actor<CounterEvents> { var counter = 0 for

    (event in channel) { when (event) { } } }
  242. fun CoroutineScope.counterActor() = actor<CounterEvents> { var counter = 0 for

    (event in channel) { when (event) { is IncCounter - > counter + + } } }
  243. fun CoroutineScope.counterActor() = actor<CounterEvents> { var counter = 0 for

    (event in channel) { when (event) { is IncCounter - > counter + + is GetCounter - > event.response.complete(counter) } } }
  244. val actor = counterActor()

  245. val actor = counterActor() suspend fun CoroutineScope.updateState() { List(100) {

    launch { repeat(1000) { actor.send(IncCounter()) 
 } } }
  246. val actor = counterActor() val response = CompletableDeferred<Int>()

  247. val actor = counterActor() val response = CompletableDeferred<Int>() actor.send(GetCounter(response))

  248. val actor = counterActor() val response = CompletableDeferred<Int>() actor.send(GetCounter(response)) println(response.await())

  249. Mutable State • Mutex • Actor

  250. Resources • Articles on testing flows, coroutine, context and more!

    
 
 https: / / codingwithmohit.com/posts/ • Talk on corotutines! 
 
 https: / / codingwithmohit.com/talks/
  251. Thank You! www.codingwithmohit.com @heyitsmohit