Slide 1

Slide 1 text

Coroutines in Kotlin Dmytro Zaitsev Team Leader @ Lóhika

Slide 2

Slide 2 text

Blocking VS Non-blocking

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

v1: Sequential fun postItem(item: Item) {
 val token = prepareToken() / / 1
 val post = submitPost(token, item) / / 2
 processPost(post) / / 3
 }

Slide 5

Slide 5 text

v2: Async callbacks fun postItem(item: Item) {
 prepareTokenAsync { token -> / / 1
 submitPostAsync(token, item) { post -> / / 2
 processPost(post) / / 3
 }
 }
 }

Slide 6

Slide 6 text

Callback hell

Slide 7

Slide 7 text

v3: Reactive (Future-based) fun postItem(item: Item) {
 observeToken()
 .concatMap { token -> observePost(token, item) }
 .subscribe { post -> processPost(post) }
 }

Slide 8

Slide 8 text

v4: Coroutines fun postItem(item: Item) = launch {
 val token = prepareToken() / / 1
 val post = submitPost(token, item) / / 2
 processPost(post) / / 3
 }
 }

Slide 9

Slide 9 text

Experimental status Kotlin 1.1 -Xcoroutines=enable kotlin.coroutines.experimental -> kotlin.coroutines

Slide 10

Slide 10 text

Experimental status New style of programming The design is not final and expected to change JetBrains still collects information and feedbacks Can and should be used in production Backwards compatibility guaranteed

Slide 11

Slide 11 text

Terminology coroutine suspending function suspending lambda suspending function type coroutine builder suspension point continuation

Slide 12

Slide 12 text

Terminology coroutine suspending function suspending lambda suspending function type coroutine builder suspension point continuation

Slide 13

Slide 13 text

A coroutine is… an instance of suspendable computation similar to a daemon thread, but very light-weight similar to a future or promise

Slide 14

Slide 14 text

Why coroutines? threads are expensive to keep and switch your code is single threaded you’ve got lots of mutable states

Slide 15

Slide 15 text

suspend fun computation that can be suspended

Slide 16

Slide 16 text

Standard API • Language support (`suspend` keyword) • low-level basic API (stdlib: kotlin.coroutines) • high-level APIs that can be used in user code

Slide 17

Slide 17 text

Low-level API (kotlin.coroutines) • kotlin.coroutines.experimental • create/start/suspendCoroutine() • Continuation interface • @RestrictSuspension annotation • kotlin.coroutines.experimental.intrinsics • suspendCoroutineOrReturn()

Slide 18

Slide 18 text

Continuation interface Continuation {
 val context: CoroutineContext
 fun resume(value: T)
 fun resumeWithException(exception: Throwable)
 }

Slide 19

Slide 19 text

Continuation / / Kotlin suspend fun submitPost( token: Token, item: Item): Post {…} / / Java/JVM Object submitPost( Token token, Item item, Continuation cont) {…} compiler magic

Slide 20

Slide 20 text

Patterns • generators/yield: C#, Python, Scala • async/await: C#, ECMAScript, Dart • channels, select: Go • actors: Scala

Slide 21

Slide 21 text

async/await / / C# way async Task ProcessImage(String url)
 {
 var image = await LoadImage(url);
 imageView.SetImage(image);
 } / / Kotlin way fun processImage(url: String) = async(UI) {
 val image = loadImageAsync(url).await()
 imageView.setImage(image)
 }

Slide 22

Slide 22 text

Generators API in kotlin.coroutines kotlin.coroutines.experimental buildIterator() buildSequence()

Slide 23

Slide 23 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 24

Slide 24 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 25

Slide 25 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 26

Slide 26 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 27

Slide 27 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 28

Slide 28 text

buildSequence {
 print("Start")
 yield(1) / / suspension point
 var prev = 0; var cur = 1
 while (true) {
 val next = prev + cur print(“Next")
 yield(next) / / suspension point
 prev = cur; cur = next
 }
 print("End") / / unreachable code
 }.take(6).forEach { print(" $it ") }
 / / Output: Start 1 Next 1 Next 2 Next 3 Next 5 Next 8

Slide 29

Slide 29 text

kotlinx.coroutines Core integration Guava JDK 8 NIO Quasar reactive Reactor RxJava 1.x Reactive Streams RxJava 2.x UI Android JavaFX Swing

Slide 30

Slide 30 text

run, runBlocking for main functions and tests

Slide 31

Slide 31 text

delay like Thread.sleep(), but non-blocking

Slide 32

Slide 32 text

launch fire and forget (Job)

Slide 33

Slide 33 text

async promise returned (Deferred + await)

Slide 34

Slide 34 text

Channel transfers values between coroutines

Slide 35

Slide 35 text

produce produces a stream of values by sending them to a channel (ProducerJob)

Slide 36

Slide 36 text

actor deals with it’s mailbox (ActorJob)

Slide 37

Slide 37 text

select waits for the result of multiple suspending functions

Slide 38

Slide 38 text

Job lifecycle New Active Cancelling Completed Cancelled

Slide 39

Slide 39 text

Job states State isActive isCompleted isCancelled New - - - Active + - - Completed - + - Cancelling - - + Cancelled - + +

Slide 40

Slide 40 text

val deferred = async(CommonPool) {
 throw SomeException("I'm thrown inside a coroutine")
 }
 try {
 deferred.await() / / re-throws
 } catch (e: SomeException) {
 log(e.message)
 } Exception handling

Slide 41

Slide 41 text

WeakReference “life hack” suspend operator fun WeakReference.invoke(): T = suspendCoroutineOrReturn { get() ?: throw CancellationException() } val activityRef = WeakReference(this)
 launch(CommonPool) {
 activityRef().expensiveComputation()
 }

Slide 42

Slide 42 text

Demo

Slide 43

Slide 43 text

A lot more left… Coroutine dispatchers Cancellation Mutable state and concurrency UI programming Reactive streams

Slide 44

Slide 44 text

Links Andrey Breslav FAQ:
 https:/ /discuss.kotlinlang.org/t/experimental-status-of-coroutines-in-1-1-and- related-compatibility-concerns/2236 Design document (KEEP):
 https:/ /github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines- informal.md Full kotlinx.coroutines API:
 http:/ /kotlin.github.io/kotlinx.coroutines Coroutines guide by Roman ELizarov:
 https:/ /github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md

Slide 45

Slide 45 text

We are hiring!

Slide 46

Slide 46 text

Thank you! @DmitriyZaitsev