Current State of
Coroutines
Presented at Kotlin Meetup 11/2017

/Guido Pio Mariotti @ OLX
What is this presentation
about?
• For an in depth introduction to coroutines look at
Introduction to Kotlin Coroutines and Deep Dives into
Coroutines on JVM from Roman Elizarov.

• What offers kotlinx-coroutines.
What are coroutines?
• Light-weight threads, is it correct?
• Instances of suspendable computation!
• Quite an old concept from 1960s.

• Present in multiple languages —> JS, Python, C#

• However, how are implemented is quite different.
What is the goal of
coroutines?
• Make concurrency simple.

• Make concurrent code explicit.
• From

val future : Future<Result> = httpRequest(request)
val result : Result = await httpRequest(request) // await keyword
• To

val future : Deferred<Result> = async { httpRequest(request) }
val result : Result = httpRequest(request)
What experimental means?
KotlinConf Keynote Recap
Even though coroutines are still labeled as an experimental
feature, we’d like to clarify the exact meaning of this status.
Coroutines are fully ready to be used in production, […].
The reason why we keep the experimental status is that it gives us
the ability to iterate on the design. Note that, even if we do make
changes to the API, the current API will remain supported, even
though it will be marked as deprecated, and we will provide the
necessary migration tools. According to our current plans, the
experimental status of coroutines will be removed in Kotlin 1.3.
Current State
• Version - 0.19.3

• kotlinx-coroutines-

• core
• [integration] - jdk8, nio, guava, quasar

• [ui] - android, javafx, swing

• [reactive] - reactive, reactor, rx1, rx2
Building blocks - 1
suspend fun launchAndRepeat() {
launch {
repeat(100_000) {
println("I'm sleeping $it...")
delay(500)
}
}
delay(1300)
}
suspend fun repeatAndLaunch() {
repeat(100_000) {
launch {
print(".")
delay(500)
}
}
delay(1300)
}
Keyword
Building blocks - 2
suspend fun launchAndRepeat() {
launch {
repeat(100_000) {
println("I'm sleeping $it...")
delay(500)
}
}
delay(1300)
}
suspend fun repeatAndLaunch() {
repeat(100_000) {
launch {
print(".")
delay(500)
}
}
delay(1300)
}
Suspending

Function
Suspending

Function
Building blocks - 3
suspend fun launchAndRepeat() {
launch {
repeat(100_000) {
println("I'm sleeping $it...")
delay(500)
}
}
delay(1300)
}
suspend fun repeatAndLaunch() {
repeat(100_000) {
launch {
print(".")
delay(500)
}
}
delay(1300)
}
Coroutine
builder
Coroutine

builder
Building blocks - 4
suspend fun launchAndRepeat() {
launch {
repeat(100_000) {
println("I'm sleeping $it...")
delay(500)
}
}
delay(1300)
}
suspend fun repeatAndLaunch() {
repeat(100_000) {
launch {
print(".")
delay(500)
}
}
delay(1300)
}
Coroutine
Coroutine
kotlinx-coroutines-core
launch
• launch is used to build a Job, a coroutine of which we
are not interested in its result.

• Some useful methods:

• cancel()
• join()
• cancelAndJoin()
• invokeOnJobCompletion(..)
async
• async is used to build a Deferred, a non-blocking
cancellable future.

• Implements Job interface.

• await() is a non-blocking method for collecting the
result of the coroutine.
async - example
fun main(args: Array<String>) = runBlocking {
val sequentialTime = measureTimeMillis {
val twoSquare = getSquareFromServer(2)
val threeSquare = getSquareFromServer(3)
println("2^2 = $twoSquare || 3^2 = $threeSquare")
}
val asyncTime = measureTimeMillis {
val twoSquare = async { getSquareFromServer(2) }
val threeSquare = async { getSquareFromServer(3) }
println("2^2 = ${twoSquare.await()} || 3^2 = ${threeSquare.await()}")
}
println("Sequential time = $sequentialTime ms”) // ~2000ms
println("Async time = $asyncTime ms”) // ~1000ms
}
suspend fun getSquareFromServer(value: Int): Int {
delay(1, TimeUnit.SECONDS) // simulate a non-blocking call to the server
return value * value
}
produce
• produce is used to create a ProducerJob, for streams
of elements production.

• Sends elements inside a channel.

• Channel can be buffered or unbuffered.
produce - example
suspend fun produce_example() {
val dotGenerator = produce(newSingleThreadContext("dot-thread")) {
println("dotGenerator is in thread [${Thread.currentThread().name}]") // working in thread [dot-thread]
while (isActive) {
send(".")
delay(50)
}
}
val dotChannel = dotGenerator.channel
val dotPyramid = produce {
println("dotPyramid starting in thread [${Thread.currentThread().name}]") // [commonPool-worker-n]
(1..10).map {
async(coroutineContext) {
println("[$it] in thread [${Thread.currentThread().name}]") // [commonPool-worker-n]
buildString { (1..it).map { append(dotChannel.receive()) } }
}
}.map { send(it.await()) }
delay(50)
println("dotPyramid ending in thread [${Thread.currentThread().name}]") // [commonPool-worker-n]
}
while (dotPyramid.isActive) {
try {
println(dotPyramid.receive())
} catch (e: ClosedReceiveChannelException) {
println("The pyramid channel has been closed")
}
}
println("Is dotGenerator active? ${dotGenerator.isActive}")
}
actor
• actor produces an ActorJob, that processes a stream of
messages.

• Used to implement the Actor Model.

• An actor is a computational entity that, in response to a message
it receives, can concurrently:

• send a finite number of messages to other actors;

• create a finite number of new actors;

• designate the behavior to be used for the next message it receives.
actor - example
sealed class Http
data class HttpRequest(val request: CompletableDeferred<Int?>) : Http()
data class HttpResponse(val response: Int) : Http()
suspend fun actor_http() {
val httpRandomNumActor = httpActor()
sendPeriodicallyRandomInt(httpRandomNumActor)
(1..10).forEach {
delay(10)
val response = CompletableDeferred<Int?>()
httpRandomNumActor.send(HttpRequest(response))
println("Sent request $it")
println("[$it] --> response ${response.await()}")
}
}
suspend fun httpActor() = actor<Http>(newFixedThreadPoolContext(3, "http-actor")) {
var latestResponse: Int? = null
for (msg in channel) {
when (msg) {
is HttpRequest -> msg.request.complete(latestResponse)
is HttpResponse -> {
latestResponse = msg.response
println("Updated response on [${Thread.currentThread().name}]")
}
}
}
}
private fun sendPeriodicallyRandomInt(httpRandomNum: ActorJob<Http>) {
launch {
while (isActive) {
httpRandomNum.send(HttpResponse(Random().nextInt()))
println("Sent response on [${Thread.currentThread().name}]")
delay(30)
}
}
}
Generators and yield
• Possibility to have Generators using Kotlin Sequence.
• yield() and yieldAll() to suspend the computation.

• Part of Kotlin stdlib.
Generators - example
import kotlin.coroutines.experimental.buildSequence
fun generator() {
fibonacci().take(5) // Lazily evaluated as expected
for (num in fibonacci()) {
if (num == 13) break
}
}
fun fibonacci() = buildSequence {
var prev = 1
println("Current value is $prev")
yield(prev)
var next = 1
while (true) {
println("Current value is $next")
val tmp = next
yield(tmp)
next = prev + tmp
prev = tmp
}
}
Select
• select offers the possibility to choose the first result
returned by two or more suspending functions, that
returns a SelectClause#N.

• Biased on the order of the functions.

• selectUnbiased solves this issue.
Select - example
suspend fun randomNumProducer(id: Int) = produce {
while (isActive) {
send("[${Thread.currentThread().name}] - Produce $id")
val sleep = Random().nextInt(50).toLong()
delay(sleep)
}
}
suspend fun selectBetween(channel1: ReceiveChannel<String>, channel2: ReceiveChannel<String>) {
select<Unit> {
channel1.onReceive {
println(it)
}
channel2.onReceiveOrNull {
println(it ?: "[${Thread.currentThread().name}] - channel is closed")
}
}
}
suspend fun select_example() {
val producer1 = randomNumProducer(1)
val producer2 = randomNumProducer(2)
repeat(5) {
selectBetween(producer1, producer2)
}
producer2.cancel()
repeat(3) {
selectBetween(producer1, producer2)
}
}
What else?
• Non-blocking Mutex.
• Channel, like the one used by actor and produce.

• Suspending function withTimeout,
withTimeoutOrNull and run.
kotlinx-coroutines-ui
What is in there?
• kotlinx-coroutines-android, offers the UI context.

• kotlinx-coroutines-javafx, offers the JavaFx context.

• kotlinx-coroutines-swing, offers the Swing context.
UI - example
fun ui_example() {
launch {
val image = async { loadImage() }
val title = async { loadTitle() }
display(image.await(), title.await())
}
}
suspend fun display(image: Image, title: String) {
run(UI) {
// display on UI thread
}
}
suspend fun loadImage(): Image =
downloadImage() // non-blocking operation for downloading the image
suspend fun loadTitle(): String =
downloadTitle() // non-blocking operation for downloading the title
kotlinx-coroutines-
integration
What is in there?
• kotlinx-coroutines-jdk8, integration with
CompletableFuture.
• kotlinx-coroutines-nio, integration with JDK7+ Async IO.
• kotlinx-coroutines-guava, integration with
ListenableFuture.
• kotlinx-coroutines-quasar, integration with Quasar
library.
CompletableFuture
• The coroutine builder future.

• Extension functions await().

• [!] CompletableFuture should be used only for
interacting with existing libraries that use it, otherwise
prefer Deferred<T>.

• [!!] get() is blocking, await() is not.
CompletableFuture -
example
suspend fun future_example() {
val readString = future(context = newSingleThreadContext("read-string")) {
stringWithDelay()
}
val readString2 = future {
stringWithDelay()
}
println("${readString.await()} - ${readString2.await()}")
}
suspend fun stringWithDelay(): String {
println("Current thread is [${Thread.currentThread().name}]")
delay(10)
println("Current thread is [${Thread.currentThread().name}]")
return "future"
}
kotlinx-coroutines-reactive
• Support for RxJava 1.x and 2.x, Reactor and Reactive
Streams.

• [!] If you’re fine with RxJava than you don’t really need
coroutines.
Recap
• Should you use coroutines in production? YES!!

• Should you use coroutines everywhere? NO!!

• They still relay on OS threads —> if you call blocking
code inside a coroutine, you block the thread on which
the coroutine is running —> Be Careful!!

• They make sense for IO bound tasks, not CPU bound
tasks!!
Resources
• Channel in Kotlin Slack - #coroutines

• KEEP - https://github.com/Kotlin/kotlin-coroutines

• Repository - https://github.com/Kotlin/kotlinx.coroutines

Current State of Coroutines

  • 1.
    Current State of Coroutines Presentedat Kotlin Meetup 11/2017 /Guido Pio Mariotti @ OLX
  • 2.
    What is thispresentation about? • For an in depth introduction to coroutines look at Introduction to Kotlin Coroutines and Deep Dives into Coroutines on JVM from Roman Elizarov. • What offers kotlinx-coroutines.
  • 3.
    What are coroutines? •Light-weight threads, is it correct? • Instances of suspendable computation! • Quite an old concept from 1960s. • Present in multiple languages —> JS, Python, C# • However, how are implemented is quite different.
  • 4.
    What is thegoal of coroutines? • Make concurrency simple. • Make concurrent code explicit. • From val future : Future<Result> = httpRequest(request) val result : Result = await httpRequest(request) // await keyword • To val future : Deferred<Result> = async { httpRequest(request) } val result : Result = httpRequest(request)
  • 5.
    What experimental means? KotlinConfKeynote Recap Even though coroutines are still labeled as an experimental feature, we’d like to clarify the exact meaning of this status. Coroutines are fully ready to be used in production, […]. The reason why we keep the experimental status is that it gives us the ability to iterate on the design. Note that, even if we do make changes to the API, the current API will remain supported, even though it will be marked as deprecated, and we will provide the necessary migration tools. According to our current plans, the experimental status of coroutines will be removed in Kotlin 1.3.
  • 6.
    Current State • Version- 0.19.3 • kotlinx-coroutines- • core • [integration] - jdk8, nio, guava, quasar • [ui] - android, javafx, swing • [reactive] - reactive, reactor, rx1, rx2
  • 7.
    Building blocks -1 suspend fun launchAndRepeat() { launch { repeat(100_000) { println("I'm sleeping $it...") delay(500) } } delay(1300) } suspend fun repeatAndLaunch() { repeat(100_000) { launch { print(".") delay(500) } } delay(1300) } Keyword
  • 8.
    Building blocks -2 suspend fun launchAndRepeat() { launch { repeat(100_000) { println("I'm sleeping $it...") delay(500) } } delay(1300) } suspend fun repeatAndLaunch() { repeat(100_000) { launch { print(".") delay(500) } } delay(1300) } Suspending
 Function Suspending
 Function
  • 9.
    Building blocks -3 suspend fun launchAndRepeat() { launch { repeat(100_000) { println("I'm sleeping $it...") delay(500) } } delay(1300) } suspend fun repeatAndLaunch() { repeat(100_000) { launch { print(".") delay(500) } } delay(1300) } Coroutine builder Coroutine
 builder
  • 10.
    Building blocks -4 suspend fun launchAndRepeat() { launch { repeat(100_000) { println("I'm sleeping $it...") delay(500) } } delay(1300) } suspend fun repeatAndLaunch() { repeat(100_000) { launch { print(".") delay(500) } } delay(1300) } Coroutine Coroutine
  • 11.
  • 12.
    launch • launch isused to build a Job, a coroutine of which we are not interested in its result. • Some useful methods: • cancel() • join() • cancelAndJoin() • invokeOnJobCompletion(..)
  • 13.
    async • async isused to build a Deferred, a non-blocking cancellable future. • Implements Job interface. • await() is a non-blocking method for collecting the result of the coroutine.
  • 14.
    async - example funmain(args: Array<String>) = runBlocking { val sequentialTime = measureTimeMillis { val twoSquare = getSquareFromServer(2) val threeSquare = getSquareFromServer(3) println("2^2 = $twoSquare || 3^2 = $threeSquare") } val asyncTime = measureTimeMillis { val twoSquare = async { getSquareFromServer(2) } val threeSquare = async { getSquareFromServer(3) } println("2^2 = ${twoSquare.await()} || 3^2 = ${threeSquare.await()}") } println("Sequential time = $sequentialTime ms”) // ~2000ms println("Async time = $asyncTime ms”) // ~1000ms } suspend fun getSquareFromServer(value: Int): Int { delay(1, TimeUnit.SECONDS) // simulate a non-blocking call to the server return value * value }
  • 15.
    produce • produce isused to create a ProducerJob, for streams of elements production. • Sends elements inside a channel. • Channel can be buffered or unbuffered.
  • 16.
    produce - example suspendfun produce_example() { val dotGenerator = produce(newSingleThreadContext("dot-thread")) { println("dotGenerator is in thread [${Thread.currentThread().name}]") // working in thread [dot-thread] while (isActive) { send(".") delay(50) } } val dotChannel = dotGenerator.channel val dotPyramid = produce { println("dotPyramid starting in thread [${Thread.currentThread().name}]") // [commonPool-worker-n] (1..10).map { async(coroutineContext) { println("[$it] in thread [${Thread.currentThread().name}]") // [commonPool-worker-n] buildString { (1..it).map { append(dotChannel.receive()) } } } }.map { send(it.await()) } delay(50) println("dotPyramid ending in thread [${Thread.currentThread().name}]") // [commonPool-worker-n] } while (dotPyramid.isActive) { try { println(dotPyramid.receive()) } catch (e: ClosedReceiveChannelException) { println("The pyramid channel has been closed") } } println("Is dotGenerator active? ${dotGenerator.isActive}") }
  • 17.
    actor • actor producesan ActorJob, that processes a stream of messages. • Used to implement the Actor Model. • An actor is a computational entity that, in response to a message it receives, can concurrently: • send a finite number of messages to other actors; • create a finite number of new actors; • designate the behavior to be used for the next message it receives.
  • 18.
    actor - example sealedclass Http data class HttpRequest(val request: CompletableDeferred<Int?>) : Http() data class HttpResponse(val response: Int) : Http() suspend fun actor_http() { val httpRandomNumActor = httpActor() sendPeriodicallyRandomInt(httpRandomNumActor) (1..10).forEach { delay(10) val response = CompletableDeferred<Int?>() httpRandomNumActor.send(HttpRequest(response)) println("Sent request $it") println("[$it] --> response ${response.await()}") } } suspend fun httpActor() = actor<Http>(newFixedThreadPoolContext(3, "http-actor")) { var latestResponse: Int? = null for (msg in channel) { when (msg) { is HttpRequest -> msg.request.complete(latestResponse) is HttpResponse -> { latestResponse = msg.response println("Updated response on [${Thread.currentThread().name}]") } } } } private fun sendPeriodicallyRandomInt(httpRandomNum: ActorJob<Http>) { launch { while (isActive) { httpRandomNum.send(HttpResponse(Random().nextInt())) println("Sent response on [${Thread.currentThread().name}]") delay(30) } } }
  • 19.
    Generators and yield •Possibility to have Generators using Kotlin Sequence. • yield() and yieldAll() to suspend the computation. • Part of Kotlin stdlib.
  • 20.
    Generators - example importkotlin.coroutines.experimental.buildSequence fun generator() { fibonacci().take(5) // Lazily evaluated as expected for (num in fibonacci()) { if (num == 13) break } } fun fibonacci() = buildSequence { var prev = 1 println("Current value is $prev") yield(prev) var next = 1 while (true) { println("Current value is $next") val tmp = next yield(tmp) next = prev + tmp prev = tmp } }
  • 21.
    Select • select offersthe possibility to choose the first result returned by two or more suspending functions, that returns a SelectClause#N. • Biased on the order of the functions. • selectUnbiased solves this issue.
  • 22.
    Select - example suspendfun randomNumProducer(id: Int) = produce { while (isActive) { send("[${Thread.currentThread().name}] - Produce $id") val sleep = Random().nextInt(50).toLong() delay(sleep) } } suspend fun selectBetween(channel1: ReceiveChannel<String>, channel2: ReceiveChannel<String>) { select<Unit> { channel1.onReceive { println(it) } channel2.onReceiveOrNull { println(it ?: "[${Thread.currentThread().name}] - channel is closed") } } } suspend fun select_example() { val producer1 = randomNumProducer(1) val producer2 = randomNumProducer(2) repeat(5) { selectBetween(producer1, producer2) } producer2.cancel() repeat(3) { selectBetween(producer1, producer2) } }
  • 23.
    What else? • Non-blockingMutex. • Channel, like the one used by actor and produce. • Suspending function withTimeout, withTimeoutOrNull and run.
  • 24.
  • 25.
    What is inthere? • kotlinx-coroutines-android, offers the UI context. • kotlinx-coroutines-javafx, offers the JavaFx context. • kotlinx-coroutines-swing, offers the Swing context.
  • 26.
    UI - example funui_example() { launch { val image = async { loadImage() } val title = async { loadTitle() } display(image.await(), title.await()) } } suspend fun display(image: Image, title: String) { run(UI) { // display on UI thread } } suspend fun loadImage(): Image = downloadImage() // non-blocking operation for downloading the image suspend fun loadTitle(): String = downloadTitle() // non-blocking operation for downloading the title
  • 27.
  • 28.
    What is inthere? • kotlinx-coroutines-jdk8, integration with CompletableFuture. • kotlinx-coroutines-nio, integration with JDK7+ Async IO. • kotlinx-coroutines-guava, integration with ListenableFuture. • kotlinx-coroutines-quasar, integration with Quasar library.
  • 29.
    CompletableFuture • The coroutinebuilder future. • Extension functions await(). • [!] CompletableFuture should be used only for interacting with existing libraries that use it, otherwise prefer Deferred<T>. • [!!] get() is blocking, await() is not.
  • 30.
    CompletableFuture - example suspend funfuture_example() { val readString = future(context = newSingleThreadContext("read-string")) { stringWithDelay() } val readString2 = future { stringWithDelay() } println("${readString.await()} - ${readString2.await()}") } suspend fun stringWithDelay(): String { println("Current thread is [${Thread.currentThread().name}]") delay(10) println("Current thread is [${Thread.currentThread().name}]") return "future" }
  • 31.
    kotlinx-coroutines-reactive • Support forRxJava 1.x and 2.x, Reactor and Reactive Streams. • [!] If you’re fine with RxJava than you don’t really need coroutines.
  • 32.
    Recap • Should youuse coroutines in production? YES!! • Should you use coroutines everywhere? NO!! • They still relay on OS threads —> if you call blocking code inside a coroutine, you block the thread on which the coroutine is running —> Be Careful!! • They make sense for IO bound tasks, not CPU bound tasks!!
  • 33.
    Resources • Channel inKotlin Slack - #coroutines • KEEP - https://github.com/Kotlin/kotlin-coroutines • Repository - https://github.com/Kotlin/kotlinx.coroutines