SlideShare a Scribd company logo
elizarov at JetBrains
Roman Elizarov
Deep dive into Coroutines
on JVM
There is no magic
Continuation Passing
Style (CPS)
A toy problem
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Direct style
Direct style
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Direct style
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Continuation
Continuation-Passing Style
fun postItem(item: Item) {
requestToken { token ->
val post = createPost(token, item)
processPost(post)
}
}
Continuation
CPS == Callbacks
Continuation-Passing Style
fun postItem(item: Item) {
requestToken { token ->
createPost(token, item) { post ->
processPost(post)
}
}
}
Coroutines Direct Style
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
How does it work?
Behind the scenes
Kotlin suspending functions
Kotlin
suspend fun createPost(token: Token, item: Item): Post { … }
CPS Transformation
Java/JVM
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
CPS Transformation
callback
Java/JVM
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
Continuation
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Continuation
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Continuation
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Continuation
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Continuation
Continuation is a generic callback interface
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation<Post> cont) { … }
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Direct to CPS
Direct code
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Continuations
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Initial continuation
Continuations
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Continuation
Continuations
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Continuation
Convert to CPS?
Callbacks?
fun postItem(item: Item) {
requestToken { token ->
createPost(token, item) { post ->
processPost(post)
}
}
}
Labels
suspend fun postItem(item: Item) {
// LABEL 0
val token = requestToken()
// LABEL 1
val post = createPost(token, item)
// LABEL 2
processPost(post)
}
Labels
suspend fun postItem(item: Item) {
switch (label) {
case 0:
val token = requestToken()
case 1:
val post = createPost(token, item)
case 2:
processPost(post)
}
}
suspend fun postItem(item: Item) {
val sm = object : CoroutineImpl { … }
switch (sm.label) {
case 0:
val token = requestToken()
case 1:
val post = createPost(token, item)
case 2:
processPost(post)
}
}
State
fun postItem(item: Item, cont: Continuation) {
val sm = object : CoroutineImpl { … }
switch (sm.label) {
case 0:
requestToken(sm)
case 1:
createPost(token, item, sm)
case 2:
processPost(post)
}
}
CPS Transform
fun postItem(item: Item, cont: Continuation) {
val sm = …
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
createPost(token, item, sm)
case 2:
processPost(post)
}
}
Save state
fun postItem(item: Item, cont: Continuation) {
val sm = object : CoroutineImpl { … }
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
createPost(token, item, sm)
case 2:
processPost(post)
}
}
Callback
State Machine as Continuation
fun postItem(item: Item, cont: Continuation) {
val sm = object : CoroutineImpl {
fun resume(…) {
postItem(null, this)
}
}
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
createPost(token, item, sm)
…
}
Callback
fun postItem(item: Item, cont: Continuation) {
val sm = cont as? ThisSM ?: object : ThisSM {
fun resume(…) {
postItem(null, this)
}
}
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
createPost(token, item, sm)
…
}
Callback
fun postItem(item: Item, cont: Continuation) {
val sm = …
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
val item = sm.item
val token = sm.result as Token
sm.label = 2
createPost(token, item, sm)
…
}
Restore state
fun postItem(item: Item, cont: Continuation) {
val sm = …
switch (sm.label) {
case 0:
sm.item = item
sm.label = 1
requestToken(sm)
case 1:
val item = sm.item
val token = sm.result as Token
sm.label = 2
createPost(token, item, sm)
…
}
Continue
State Machine vs Callbacks
fun postItem(item: Item) {
requestToken { token ->
createPost(token, item) { post ->
processPost(post)
}
}
}
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
State Machine vs Callbacks
fun postItem(item: Item) {
requestToken { token ->
createPost(token, item) { post ->
processPost(post)
}
}
}
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Reuse closure / state object
Create new closure
State Machine vs Callbacks
suspend fun postItems(items: List<Item>) {
for (item in items) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Easy loops and
higher-order functions
State Machine vs Callbacks
fun postItems(items: List<Item>) {
…
}
suspend fun postItems(items: List<Item>) {
for (item in items) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
A horrid callback mess
Easy loops and
higher-order functions
Integration
Zoo of futures on JVM
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
suspend fun <T> Call<T>.await(): T {
…
}
Callbacks everywhere
suspend fun <T> Call<T>.await(): T {
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
// todo
}
override fun onFailure(call: Call<T>, t: Throwable) {
// todo
}
})
}
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)
}
})
}
suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T
suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T
Regular function
Inspired by call/cc from Scheme
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)
}
})
}
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)
}
})
}
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)
}
})
}
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
Out-of-the box integrations
kotlinx-coroutines-core
jdk8
guava
nio
reactor
rx1
rx2
Contributions are welcome
Coroutine context
What thread it resumes on?
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Continuation
It depends!
What thread it resumes on?
fun postItem(item: Item) {
launch(UI) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Continuation
Continuation Interceptor
interface ContinuationInterceptor : CoroutineContext.Element {
companion object Key : CoroutineContext.Key<ContinuationInterceptor>
fun <T> interceptContinuation(continuation: Continuation<T>):
Continuation<T>
}
Continuation Interceptor
interface ContinuationInterceptor : CoroutineContext.Element {
companion object Key : CoroutineContext.Key<ContinuationInterceptor>
fun <T> interceptContinuation(continuation: Continuation<T>):
Continuation<T>
}
Continuation Interceptor
interface ContinuationInterceptor : CoroutineContext.Element {
companion object Key : CoroutineContext.Key<ContinuationInterceptor>
fun <T> interceptContinuation(continuation: Continuation<T>):
Continuation<T>
}
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
Starting coroutines
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T>
Coroutine builder
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T>
A regular function
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T>
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T> suspending lambda
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T> {
val future = CompletableFuture<T>()
block.startCoroutine(…)
return future
}
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T> {
val future = CompletableFuture<T>()
block.startCoroutine(…)
return future
}
fun <T> future(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> T
): CompletableFuture<T> {
val future = CompletableFuture<T>()
block.startCoroutine(completion = object : Continuation<T> {
…
})
return future
}
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
}
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
}
That’s all, folks!
Job cancellation
Launch coroutine builder
fun launch(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> Unit
): Job { … }
Launching coroutine
val job = launch {
…
}
val job = launch {
…
}
job.join()
val job = launch {
…
}
job.join()
job.cancel()
Job
interface Job : CoroutineContext.Element {
companion object Key : CoroutineContext.Key<Job>
…
}
Using coroutine context
launch {
val job = coroutineContext[Job]!!
…
}
Using coroutine context
launch {
val job = coroutineContext[Job]!!
val interceptor = coroutineContext[CoroutineInterceptor]!!
…
}
Timeouts
launch {
withTimeout(10, TimeUnit.SECONDS) {
…
}
}
Cooperative cancellation
Cooperative cancellation
launch {
while (true) {
…
}
}
Cooperative cancellation
launch {
while (isActive) {
…
}
}
Cooperative cancellation
launch {
while (true) {
delay(…)
…
}
}
Cancellable suspension
suspend fun <T> Call<T>.await(): T =
suspendCancellableCoroutine { cont ->
enqueue(…)
}
Cancellable continuation
suspend fun <T> Call<T>.await(): T =
suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
enqueue(…)
}
Completion handler
suspend fun <T> Call<T>.await(): T =
suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
enqueue(…)
cont.invokeOnCompletion {
this@await.cancel()
}
}
Completion handler
suspend fun <T> Call<T>.await(): T =
suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
enqueue(…)
cont.invokeOnCompletion {
this@await.cancel()
}
}
Communicating Sequential
Processes (CSP)
Shared Mutable State
@stefanobaghino
The choice
Shared
Mutable State
Share by
Communicating
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)
}
}
}
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)
}
}
}
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)
}
}
}
Launch
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)
}
}
}
Child coroutine
Coroutine body
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)
}
}
}
Sequential code!
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)
}
}
}
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)
}
}
}
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)
}
}
}
Demo
Actors
The other way to look at CSP
The choice
Named
channels
Named
coroutines
Actor == named coroutine & inbox channel
Example
fun main(args: Array<String>) = runBlocking<Unit> {
val printer = actor<Int>(coroutineContext) {
for (i in channel) {
println(i)
}
}
launch(coroutineContext) {
repeat(10) { i ->
delay(100)
printer.send(i)
}
printer.close()
}
}
Actor coroutine builder
fun main(args: Array<String>) = runBlocking<Unit> {
val printer = actor<Int>(coroutineContext) {
for (i in channel) {
println(i)
}
}
launch(coroutineContext) {
repeat(10) { i ->
delay(100)
printer.send(i)
}
printer.close()
}
}
Actor body
fun main(args: Array<String>) = runBlocking<Unit> {
val printer = actor<Int>(coroutineContext) {
for (i in channel) {
println(i)
}
}
launch(coroutineContext) {
repeat(10) { i ->
delay(100)
printer.send(i)
}
printer.close()
}
}
Sequential!
Interacting with an actor
fun main(args: Array<String>) = runBlocking<Unit> {
val printer = actor<Int>(coroutineContext) {
for (i in channel) {
println(i)
}
}
launch(coroutineContext) {
repeat(10) { i ->
delay(100)
printer.send(i)
}
printer.close()
}
}
References
Guide to kotlinx.coroutines
by example
https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md
• Basics
• Cancellation and Timeouts
• Composition
• Coroutine contexts
• Channels
• Shared Mutable State and Concurrency
• Select expressions
#kotlinconf17
relizarov
elizarov at JetBrains
Roman Elizarov
Thank you
Any questions?

More Related Content

What's hot (20)

PDF
Kotlin Coroutines in Practice @ KotlinConf 2018
Roman Elizarov
 
PDF
Kotlin Coroutines Reloaded
Roman Elizarov
 
PDF
Asynchronous JavaScript Programming with Callbacks & Promises
Hùng Nguyễn Huy
 
PDF
Idiomatic Kotlin
intelliyole
 
PPTX
Flask
Mamta Kumari
 
PDF
An introduction to Rust: the modern programming language to develop safe and ...
Claudio Capobianco
 
PPTX
OWASP AppSecCali 2015 - Marshalling Pickles
Christopher Frohoff
 
PDF
Introduction to Kotlin coroutines
Roman Elizarov
 
PDF
Intro to Asynchronous Javascript
Garrett Welson
 
PDF
JavaScript: Variables and Functions
Jussi Pohjolainen
 
PDF
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
PPTX
Node js introduction
Joseph de Castelnau
 
PPTX
Python/Flask Presentation
Parag Mujumdar
 
PPTX
Sequelize
Tarek Raihan
 
PPTX
JavaScript Promises
L&T Technology Services Limited
 
PDF
Angular Advanced Routing
Laurent Duveau
 
PPT
Hibernate
Sunil OS
 
PDF
Dataflow with Apache NiFi
DataWorks Summit/Hadoop Summit
 
PDF
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
Christopher Frohoff
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Roman Elizarov
 
Kotlin Coroutines Reloaded
Roman Elizarov
 
Asynchronous JavaScript Programming with Callbacks & Promises
Hùng Nguyễn Huy
 
Idiomatic Kotlin
intelliyole
 
An introduction to Rust: the modern programming language to develop safe and ...
Claudio Capobianco
 
OWASP AppSecCali 2015 - Marshalling Pickles
Christopher Frohoff
 
Introduction to Kotlin coroutines
Roman Elizarov
 
Intro to Asynchronous Javascript
Garrett Welson
 
JavaScript: Variables and Functions
Jussi Pohjolainen
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
Node js introduction
Joseph de Castelnau
 
Python/Flask Presentation
Parag Mujumdar
 
Sequelize
Tarek Raihan
 
JavaScript Promises
L&T Technology Services Limited
 
Angular Advanced Routing
Laurent Duveau
 
Hibernate
Sunil OS
 
Dataflow with Apache NiFi
DataWorks Summit/Hadoop Summit
 
OWASP SD: Deserialize My Shorts: Or How I Learned To Start Worrying and Hate ...
Christopher Frohoff
 

Viewers also liked (20)

PPT
Using Simplicity to Make Hard Big Data Problems Easy
nathanmarz
 
PDF
Анализ количества посетителей на сайте [Считаем уникальные элементы]
Qrator Labs
 
PDF
ReqLabs PechaKucha Евгений Сафроненко
PechaKucha Ukraine
 
PDF
HyperLogLog in Hive - How to count sheep efficiently?
bzamecnik
 
PDF
Probabilistic data structures. Part 2. Cardinality
Andrii Gakhov
 
PDF
Big Data aggregation techniques
Valentin Logvinskiy
 
PDF
Big Data Day LA 2015 - Large Scale Distinct Count -- The HyperLogLog algorith...
Data Con LA
 
PPTX
Probabilistic data structures
shrinivasvasala
 
PPTX
Hyper loglog
nybon
 
PPTX
Walk through an enterprise Linux migration
Rogue Wave Software
 
PPTX
Graduating To Go - A Jumpstart into the Go Programming Language
Kaylyn Gibilterra
 
PDF
Scale Up with Lock-Free Algorithms @ JavaOne
Roman Elizarov
 
PDF
numPYNQ @ NGCLE@e-Novia 15.11.2017
NECST Lab @ Politecnico di Milano
 
PPTX
What in the World is Going on at The Linux Foundation?
Black Duck by Synopsys
 
PPTX
Docker Networking
Kingston Smiler
 
PPTX
Communication hardware
Hans Mallen
 
PPTX
In-Memory Computing Essentials for Architects and Engineers
Denis Magda
 
PPT
DevRomagna / Golang Intro
Simone Gentili
 
PDF
Advanced memory allocation
Joris Bonnefoy
 
PDF
[若渴計畫] Challenges and Solutions of Window Remote Shellcode
Aj MaChInE
 
Using Simplicity to Make Hard Big Data Problems Easy
nathanmarz
 
Анализ количества посетителей на сайте [Считаем уникальные элементы]
Qrator Labs
 
ReqLabs PechaKucha Евгений Сафроненко
PechaKucha Ukraine
 
HyperLogLog in Hive - How to count sheep efficiently?
bzamecnik
 
Probabilistic data structures. Part 2. Cardinality
Andrii Gakhov
 
Big Data aggregation techniques
Valentin Logvinskiy
 
Big Data Day LA 2015 - Large Scale Distinct Count -- The HyperLogLog algorith...
Data Con LA
 
Probabilistic data structures
shrinivasvasala
 
Hyper loglog
nybon
 
Walk through an enterprise Linux migration
Rogue Wave Software
 
Graduating To Go - A Jumpstart into the Go Programming Language
Kaylyn Gibilterra
 
Scale Up with Lock-Free Algorithms @ JavaOne
Roman Elizarov
 
numPYNQ @ NGCLE@e-Novia 15.11.2017
NECST Lab @ Politecnico di Milano
 
What in the World is Going on at The Linux Foundation?
Black Duck by Synopsys
 
Docker Networking
Kingston Smiler
 
Communication hardware
Hans Mallen
 
In-Memory Computing Essentials for Architects and Engineers
Denis Magda
 
DevRomagna / Golang Intro
Simone Gentili
 
Advanced memory allocation
Joris Bonnefoy
 
[若渴計畫] Challenges and Solutions of Window Remote Shellcode
Aj MaChInE
 
Ad

Similar to Deep dive into Coroutines on JVM @ KotlinConf 2017 (20)

PDF
Dive into kotlins coroutines
Freddie Wang
 
PDF
Fresh Async with Kotlin @ QConSF 2017
Roman Elizarov
 
PDF
Kotlin coroutine - behind the scenes
Anh Vu
 
PDF
Fresh Async with Kotlin
C4Media
 
PDF
Coroutines in Kotlin. In-depth review
Dmytro Zaitsev
 
PDF
Coroutines in Kotlin. UA Mobile 2017.
UA Mobile
 
PPTX
Kotlin coroutines
TSE-JU LIN(Louis)
 
PDF
Dip into Coroutines - KTUG Munich 202303
Alex Semin
 
PDF
Should it be routine to use coroutines?
Ion Stefan Brosteanu
 
PDF
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
NAVER Engineering
 
PDF
Kotlin - Coroutine
Sean Tsai
 
PDF
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kirill Rozov
 
PPTX
Coroutines talk ppt
Shahroz Khan
 
PDF
Kotlin의 코루틴은 어떻게 동작하는가
Chang W. Doh
 
PDF
JVMLS 2016. Coroutines in Kotlin
Andrey Breslav
 
PPTX
2019-01-29 - Demystifying Kotlin Coroutines
Eamonn Boyle
 
PDF
Programação assíncrona utilizando Coroutines
Diego Gonçalves Santos
 
PDF
Structured concurrency with Kotlin Coroutines
Vadims Savjolovs
 
PDF
Kotlin Coroutines. Flow is coming
Kirill Rozov
 
PPTX
Kotlin coroutines and spring framework
Sunghyouk Bae
 
Dive into kotlins coroutines
Freddie Wang
 
Fresh Async with Kotlin @ QConSF 2017
Roman Elizarov
 
Kotlin coroutine - behind the scenes
Anh Vu
 
Fresh Async with Kotlin
C4Media
 
Coroutines in Kotlin. In-depth review
Dmytro Zaitsev
 
Coroutines in Kotlin. UA Mobile 2017.
UA Mobile
 
Kotlin coroutines
TSE-JU LIN(Louis)
 
Dip into Coroutines - KTUG Munich 202303
Alex Semin
 
Should it be routine to use coroutines?
Ion Stefan Brosteanu
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
NAVER Engineering
 
Kotlin - Coroutine
Sean Tsai
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kirill Rozov
 
Coroutines talk ppt
Shahroz Khan
 
Kotlin의 코루틴은 어떻게 동작하는가
Chang W. Doh
 
JVMLS 2016. Coroutines in Kotlin
Andrey Breslav
 
2019-01-29 - Demystifying Kotlin Coroutines
Eamonn Boyle
 
Programação assíncrona utilizando Coroutines
Diego Gonçalves Santos
 
Structured concurrency with Kotlin Coroutines
Vadims Savjolovs
 
Kotlin Coroutines. Flow is coming
Kirill Rozov
 
Kotlin coroutines and spring framework
Sunghyouk Bae
 
Ad

More from Roman Elizarov (17)

PDF
Lock-free algorithms for Kotlin Coroutines
Roman Elizarov
 
PPTX
Non blocking programming and waiting
Roman Elizarov
 
PDF
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
PDF
Многопоточное Программирование - Теория и Практика
Roman Elizarov
 
PDF
Wait for your fortune without Blocking!
Roman Elizarov
 
PDF
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
PDF
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
PDF
Why GC is eating all my CPU?
Roman Elizarov
 
PDF
Многопоточные Алгоритмы (для BitByte 2014)
Roman Elizarov
 
PDF
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Roman Elizarov
 
PPTX
DIY Java Profiling
Roman Elizarov
 
PDF
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
PPTX
Java Serialization Facts and Fallacies
Roman Elizarov
 
PPTX
Millions quotes per second in pure java
Roman Elizarov
 
PPTX
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
PPTX
The theory of concurrent programming for a seasoned programmer
Roman Elizarov
 
PPTX
Пишем самый быстрый хеш для кэширования данных
Roman Elizarov
 
Lock-free algorithms for Kotlin Coroutines
Roman Elizarov
 
Non blocking programming and waiting
Roman Elizarov
 
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
Многопоточное Программирование - Теория и Практика
Roman Elizarov
 
Wait for your fortune without Blocking!
Roman Elizarov
 
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
Why GC is eating all my CPU?
Roman Elizarov
 
Многопоточные Алгоритмы (для BitByte 2014)
Roman Elizarov
 
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Roman Elizarov
 
DIY Java Profiling
Roman Elizarov
 
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
Java Serialization Facts and Fallacies
Roman Elizarov
 
Millions quotes per second in pure java
Roman Elizarov
 
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
Roman Elizarov
 
The theory of concurrent programming for a seasoned programmer
Roman Elizarov
 
Пишем самый быстрый хеш для кэширования данных
Roman Elizarov
 

Recently uploaded (20)

PPTX
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
PDF
Java 25 and Beyond - A Roadmap of Innovations
Ana-Maria Mihalceanu
 
PPTX
Enabling the Digital Artisan – keynote at ICOCI 2025
Alan Dix
 
PDF
Darley - FIRST Copenhagen Lightning Talk (2025-06-26) Epochalypse 2038 - Time...
treyka
 
PPTX
Paycifi - Programmable Trust_Breakfast_PPTXT
FinTech Belgium
 
PPTX
MARTSIA: A Tool for Confidential Data Exchange via Public Blockchain - Pitch ...
Michele Kryston
 
PDF
Why aren't you using FME Flow's CPU Time?
Safe Software
 
PDF
Hello I'm "AI" Your New _________________
Dr. Tathagat Varma
 
PDF
Database Benchmarking for Performance Masterclass: Session 1 - Benchmarking F...
ScyllaDB
 
PPTX
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
PDF
My Journey from CAD to BIM: A True Underdog Story
Safe Software
 
PDF
From Chatbot to Destroyer of Endpoints - Can ChatGPT Automate EDR Bypasses (1...
Priyanka Aash
 
PDF
UiPath Agentic AI ile Akıllı Otomasyonun Yeni Çağı
UiPathCommunity
 
PDF
Plugging AI into everything: Model Context Protocol Simplified.pdf
Abati Adewale
 
PDF
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
PDF
FME as an Orchestration Tool with Principles From Data Gravity
Safe Software
 
PDF
Automating the Geo-Referencing of Historic Aerial Photography in Flanders
Safe Software
 
PDF
How to Visualize the ​Spatio-Temporal Data Using CesiumJS​
SANGHEE SHIN
 
PDF
EIS-Webinar-Engineering-Retail-Infrastructure-06-16-2025.pdf
Earley Information Science
 
PDF
Python Conference Singapore - 19 Jun 2025
ninefyi
 
UserCon Belgium: Honey, VMware increased my bill
stijn40
 
Java 25 and Beyond - A Roadmap of Innovations
Ana-Maria Mihalceanu
 
Enabling the Digital Artisan – keynote at ICOCI 2025
Alan Dix
 
Darley - FIRST Copenhagen Lightning Talk (2025-06-26) Epochalypse 2038 - Time...
treyka
 
Paycifi - Programmable Trust_Breakfast_PPTXT
FinTech Belgium
 
MARTSIA: A Tool for Confidential Data Exchange via Public Blockchain - Pitch ...
Michele Kryston
 
Why aren't you using FME Flow's CPU Time?
Safe Software
 
Hello I'm "AI" Your New _________________
Dr. Tathagat Varma
 
Database Benchmarking for Performance Masterclass: Session 1 - Benchmarking F...
ScyllaDB
 
CapCut Pro Crack For PC Latest Version {Fully Unlocked} 2025
pcprocore
 
My Journey from CAD to BIM: A True Underdog Story
Safe Software
 
From Chatbot to Destroyer of Endpoints - Can ChatGPT Automate EDR Bypasses (1...
Priyanka Aash
 
UiPath Agentic AI ile Akıllı Otomasyonun Yeni Çağı
UiPathCommunity
 
Plugging AI into everything: Model Context Protocol Simplified.pdf
Abati Adewale
 
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
FME as an Orchestration Tool with Principles From Data Gravity
Safe Software
 
Automating the Geo-Referencing of Historic Aerial Photography in Flanders
Safe Software
 
How to Visualize the ​Spatio-Temporal Data Using CesiumJS​
SANGHEE SHIN
 
EIS-Webinar-Engineering-Retail-Infrastructure-06-16-2025.pdf
Earley Information Science
 
Python Conference Singapore - 19 Jun 2025
ninefyi
 

Deep dive into Coroutines on JVM @ KotlinConf 2017

  • 1. elizarov at JetBrains Roman Elizarov Deep dive into Coroutines on JVM
  • 2. There is no magic
  • 4. A toy problem fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Direct style
  • 5. Direct style fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 6. Direct style fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Continuation
  • 7. Continuation-Passing Style fun postItem(item: Item) { requestToken { token -> val post = createPost(token, item) processPost(post) } } Continuation CPS == Callbacks
  • 8. Continuation-Passing Style fun postItem(item: Item) { requestToken { token -> createPost(token, item) { post -> processPost(post) } } }
  • 9. Coroutines Direct Style suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 10. How does it work? Behind the scenes
  • 11. Kotlin suspending functions Kotlin suspend fun createPost(token: Token, item: Item): Post { … }
  • 12. CPS Transformation Java/JVM suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … }
  • 13. CPS Transformation callback Java/JVM suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … }
  • 14. Continuation suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 15. Continuation suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 16. Continuation suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 17. Continuation suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 18. Continuation Continuation is a generic callback interface suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 20. Direct code suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 21. Continuations suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Initial continuation
  • 22. Continuations suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Continuation
  • 23. Continuations suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Continuation Convert to CPS?
  • 24. Callbacks? fun postItem(item: Item) { requestToken { token -> createPost(token, item) { post -> processPost(post) } } }
  • 25. Labels suspend fun postItem(item: Item) { // LABEL 0 val token = requestToken() // LABEL 1 val post = createPost(token, item) // LABEL 2 processPost(post) }
  • 26. Labels suspend fun postItem(item: Item) { switch (label) { case 0: val token = requestToken() case 1: val post = createPost(token, item) case 2: processPost(post) } }
  • 27. suspend fun postItem(item: Item) { val sm = object : CoroutineImpl { … } switch (sm.label) { case 0: val token = requestToken() case 1: val post = createPost(token, item) case 2: processPost(post) } } State
  • 28. fun postItem(item: Item, cont: Continuation) { val sm = object : CoroutineImpl { … } switch (sm.label) { case 0: requestToken(sm) case 1: createPost(token, item, sm) case 2: processPost(post) } } CPS Transform
  • 29. fun postItem(item: Item, cont: Continuation) { val sm = … switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: createPost(token, item, sm) case 2: processPost(post) } } Save state
  • 30. fun postItem(item: Item, cont: Continuation) { val sm = object : CoroutineImpl { … } switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: createPost(token, item, sm) case 2: processPost(post) } } Callback State Machine as Continuation
  • 31. fun postItem(item: Item, cont: Continuation) { val sm = object : CoroutineImpl { fun resume(…) { postItem(null, this) } } switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: createPost(token, item, sm) … } Callback
  • 32. fun postItem(item: Item, cont: Continuation) { val sm = cont as? ThisSM ?: object : ThisSM { fun resume(…) { postItem(null, this) } } switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: createPost(token, item, sm) … } Callback
  • 33. fun postItem(item: Item, cont: Continuation) { val sm = … switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: val item = sm.item val token = sm.result as Token sm.label = 2 createPost(token, item, sm) … } Restore state
  • 34. fun postItem(item: Item, cont: Continuation) { val sm = … switch (sm.label) { case 0: sm.item = item sm.label = 1 requestToken(sm) case 1: val item = sm.item val token = sm.result as Token sm.label = 2 createPost(token, item, sm) … } Continue
  • 35. State Machine vs Callbacks fun postItem(item: Item) { requestToken { token -> createPost(token, item) { post -> processPost(post) } } } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 36. State Machine vs Callbacks fun postItem(item: Item) { requestToken { token -> createPost(token, item) { post -> processPost(post) } } } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Reuse closure / state object Create new closure
  • 37. State Machine vs Callbacks suspend fun postItems(items: List<Item>) { for (item in items) { val token = requestToken() val post = createPost(token, item) processPost(post) } } Easy loops and higher-order functions
  • 38. State Machine vs Callbacks fun postItems(items: List<Item>) { … } suspend fun postItems(items: List<Item>) { for (item in items) { val token = requestToken() val post = createPost(token, item) processPost(post) } } A horrid callback mess Easy loops and higher-order functions
  • 40. Zoo of futures on JVM
  • 41. interface Service { fun createPost(token: Token, item: Item): Call<Post> }
  • 42. interface Service { fun createPost(token: Token, item: Item): Call<Post> } suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await()
  • 43. suspend fun <T> Call<T>.await(): T { … }
  • 44. Callbacks everywhere suspend fun <T> Call<T>.await(): T { enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { // todo } override fun onFailure(call: Call<T>, t: Throwable) { // todo } }) }
  • 45. 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) } }) }
  • 46. suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T
  • 47. suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T Regular function Inspired by call/cc from Scheme
  • 48. 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) } }) }
  • 49. 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) } }) }
  • 50. 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) } }) }
  • 51. 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
  • 54. What thread it resumes on? suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Continuation It depends!
  • 55. What thread it resumes on? fun postItem(item: Item) { launch(UI) { val token = requestToken() val post = createPost(token, item) processPost(post) } } Continuation
  • 56. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }
  • 57. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }
  • 58. Continuation Interceptor interface ContinuationInterceptor : CoroutineContext.Element { companion object Key : CoroutineContext.Key<ContinuationInterceptor> fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> }
  • 59. 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
  • 61. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> Coroutine builder
  • 62. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> A regular function
  • 63. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T>
  • 64. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> suspending lambda
  • 65. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block.startCoroutine(…) return future }
  • 66. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block.startCoroutine(…) return future }
  • 67. fun <T> future( context: CoroutineContext = DefaultDispatcher, block: suspend () -> T ): CompletableFuture<T> { val future = CompletableFuture<T>() block.startCoroutine(completion = object : Continuation<T> { … }) return future }
  • 68. 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 }
  • 69. 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 } That’s all, folks!
  • 71. Launch coroutine builder fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job { … }
  • 72. Launching coroutine val job = launch { … }
  • 73. val job = launch { … } job.join()
  • 74. val job = launch { … } job.join() job.cancel()
  • 75. Job interface Job : CoroutineContext.Element { companion object Key : CoroutineContext.Key<Job> … }
  • 76. Using coroutine context launch { val job = coroutineContext[Job]!! … }
  • 77. Using coroutine context launch { val job = coroutineContext[Job]!! val interceptor = coroutineContext[CoroutineInterceptor]!! … }
  • 82. Cooperative cancellation launch { while (true) { delay(…) … } }
  • 83. Cancellable suspension suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont -> enqueue(…) }
  • 84. Cancellable continuation suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue(…) }
  • 85. Completion handler suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue(…) cont.invokeOnCompletion { [email protected]() } }
  • 86. Completion handler suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont: CancellableContinuation<T> -> enqueue(…) cont.invokeOnCompletion { [email protected]() } }
  • 90. 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) } } }
  • 91. 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) } } }
  • 92. 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) } } }
  • 93. Launch 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) } } } Child coroutine
  • 94. Coroutine body 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) } } } Sequential code!
  • 95. 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) } } }
  • 96. 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) } } }
  • 97. 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) } } }
  • 98. Demo
  • 99. Actors The other way to look at CSP
  • 100. The choice Named channels Named coroutines Actor == named coroutine & inbox channel
  • 101. Example fun main(args: Array<String>) = runBlocking<Unit> { val printer = actor<Int>(coroutineContext) { for (i in channel) { println(i) } } launch(coroutineContext) { repeat(10) { i -> delay(100) printer.send(i) } printer.close() } }
  • 102. Actor coroutine builder fun main(args: Array<String>) = runBlocking<Unit> { val printer = actor<Int>(coroutineContext) { for (i in channel) { println(i) } } launch(coroutineContext) { repeat(10) { i -> delay(100) printer.send(i) } printer.close() } }
  • 103. Actor body fun main(args: Array<String>) = runBlocking<Unit> { val printer = actor<Int>(coroutineContext) { for (i in channel) { println(i) } } launch(coroutineContext) { repeat(10) { i -> delay(100) printer.send(i) } printer.close() } } Sequential!
  • 104. Interacting with an actor fun main(args: Array<String>) = runBlocking<Unit> { val printer = actor<Int>(coroutineContext) { for (i in channel) { println(i) } } launch(coroutineContext) { repeat(10) { i -> delay(100) printer.send(i) } printer.close() } }
  • 106. Guide to kotlinx.coroutines by example https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md • Basics • Cancellation and Timeouts • Composition • Coroutine contexts • Channels • Shared Mutable State and Concurrency • Select expressions
  • 107. #kotlinconf17 relizarov elizarov at JetBrains Roman Elizarov Thank you Any questions?