deep dive into coroutines on jvm
play

Deep dive into Coroutines on JVM Roman Elizarov elizarov at - PowerPoint PPT Presentation

Deep dive into Coroutines on JVM Roman Elizarov elizarov at JetBrains There is no magic Continuation Passing Style (CPS) A toy problem fun postItem(item: Item) { val token = requestToken () val post = createPost (token, item) processPost


  1. Install callback suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont -> enqueue( object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response. isSuccessful ) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }

  2. Analyze response suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont -> enqueue( object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response. isSuccessful ) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }

  3. Analyze response suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont -> enqueue( object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response. isSuccessful ) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) } That’s all

  4. Out-of-the box integrations reactor guava jdk8 rx2 rx1 nio kotlinx-coroutines-core Contributions are welcome

  5. Coroutine context

  6. What thread it resumes on? suspend fun postItem(item: Item) { val token = requestToken () val post = createPost (token, item) processPost (post) Continuation } It depends!

  7. What thread it resumes on? fun postItem(item: Item) { launch (UI) { val token = requestToken () val post = createPost (token, item) processPost (post) Continuation } }

  8. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }

  9. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }

  10. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }

  11. Dispatched continuation class DispatchedContinuation< in T>( val dispatcher : CoroutineDispatcher, val continuation : Continuation<T> ): Continuation<T> by continuation { override fun resume(value: T) { dispatcher .dispatch(context, DispatchTask( … )) } … } Dispatches execution to another thread

  12. Starting coroutines

  13. Coroutine builder fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T>

  14. A regular function fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T>

  15. fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T>

  16. fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T> suspending lambda

  17. fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block. startCoroutine (…) return future }

  18. fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block. startCoroutine (…) return future }

  19. fun <T> future( context: CoroutineContext = DefaultDispatcher , block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block. startCoroutine (completion = object : Continuation<T> { … }) return future }

  20. fun <T> future(…): CompletableFuture<T> { val future = CompletableFuture<T>() block. startCoroutine (completion = object : Continuation<T> { override val context : CoroutineContext get () = context override fun resume(value: T) { future.complete(value) } override fun resumeWithException(exception: Throwable) { future.completeExceptionally(exception) } }) return future }

  21. fun <T> future(…): CompletableFuture<T> { val future = CompletableFuture<T>() block. startCoroutine (completion = object : Continuation<T> { override val context : CoroutineContext get () = context override fun resume(value: T) { future.complete(value) } override fun resumeWithException(exception: Throwable) { future.completeExceptionally(exception) } }) That’s all, folks! return future }

  22. Job cancellation

  23. Launch coroutine builder fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job { … }

  24. Launching coroutine val job = launch { … }

  25. val job = launch { … } job.join()

  26. val job = launch { … } job.join() job.cancel()

  27. Job interface Job : CoroutineContext.Element { companion object Key : CoroutineContext.Key<Job> … }

  28. Using coroutine context launch { val job = coroutineContext [Job]!! … }

  29. Using coroutine context launch { val job = coroutineContext [Job]!! val interceptor = coroutineContext [CoroutineInterceptor]!! … }

  30. Timeouts launch { withTimeout (10, TimeUnit. SECONDS ) { … } }

  31. Cooperative cancellation

  32. Cooperative cancellation launch { while ( true ) { … } }

  33. Cooperative cancellation launch { while ( isActive ) { … } }

  34. Cooperative cancellation launch { while ( true ) { delay (…) … } }

  35. Cancellable suspension suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont -> enqueue( … ) }

  36. Cancellable continuation suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue( … ) }

  37. Completion handler suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue( … ) cont.invokeOnCompletion { this @await.cancel() } }

  38. Completion handler suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue( … ) cont.invokeOnCompletion { this @await.cancel() } }

  39. Communicating Sequential Processes (CSP)

  40. Shared Mutable State @stefanobaghino

  41. The choice Shared Share by Mutable State Communicating

  42. Example fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  43. Main coroutine fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  44. Channel fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  45. Launch fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) Child coroutine } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  46. Coroutine body fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) Sequential code! } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  47. Send fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  48. Close fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  49. Receive for loop fun main(args: Array<String>) = runBlocking <Unit> { val chan = Channel <Int>() launch ( coroutineContext ) { repeat (10) { i -> delay (100) chan.send(i) } chan.close() } launch ( coroutineContext ) { for (i in chan) { println (i) } } }

  50. Demo

  51. Actors The other way to look at CSP

  52. The choice Named Named channels coroutines Actor == named coroutine & inbox channel

Recommend


More recommend