The Kotlin programming language
• Releases:
• Kotlin 1.0 - February 2016
• Kotlin 1.1 - March 2017
• Used in JetBrains
• Used in Expedia, NBC News, Digital, Netflix,
Amex, Pinterest, and others
Slide 3
Slide 3 text
Kotlin Coroutines
• the key new feature in Kotlin 1.1
• brings the support of:
• async/await,
• yield,
• and more
Slide 4
Slide 4 text
Coroutine
a main routine and a subroutine
vs
coroutines, which call on each other
• the term from 1960s
• was used in “The Art of Computer Programming”
by Donald Knuth
C# way
async Task LoadImageAsync(String url)
{
/* do the work */
}
Kotlin way
fun loadImageAsync() = async {
/* do the work */
}
Slide 12
Slide 12 text
C# way
async Task ProcessImage(String url)
{
var image = await LoadImage(url);
myUI.SetImage(image);
}
Kotlin way
fun processImage() = async {
val image = loadImageAsync().await()
myUI.setImage(image)
}
Slide 13
Slide 13 text
coroutines
async/await
Language
Library
async/await - functions
defined in the standard library
Slide 14
Slide 14 text
Threads & Coroutines
Slide 15
Slide 15 text
Asynchronous
computations:
how?
Slide 16
Slide 16 text
New thread for every computation
too
expensive
Slide 17
Slide 17 text
Executor
• fixed number
of threads
• adding tasks
• but: difficult to manage
dependencies
Slide 18
Slide 18 text
Coroutine = “lightweight thread”
computation that
can be suspended
Slide 19
Slide 19 text
Coroutine = “lightweight thread”
computation that
can be suspended
Slide 20
Slide 20 text
suspend fun
computation that can be suspended
Slide 21
Slide 21 text
Why suspend?
Slide 22
Slide 22 text
Blocking thread
idle
too expensive
Slide 23
Slide 23 text
thenCombine / zip
CompletableFutures / Rx
computation in
a callback
Slide 24
Slide 24 text
1
2
3
• computation that can
be suspended
• thread is not blocking!
Coroutines
Slide 25
Slide 25 text
suspending call
Back to image example
fun loadImageAsync() = async {
/* do the work */
}
fun processImage() = async {
val image = loadImageAsync().await()
myUI.setImage(image)
}
Slide 26
Slide 26 text
fun loadImageAsync(): Deferred = async {
/* do the work */
}
interface Deferred {
suspend fun await(): T
}
await is a suspend function
await suspends computation
loadImageAsync
processImage
2
loadImageAsync
processImage
3
…and continues it when result is ready
On which thread?
Slide 29
Slide 29 text
Q: On which thread
can the coroutine be continued?
A: You specify that.
Slide 30
Slide 30 text
Continue in any thread from thread pool
async(CommonPool) {
...
}
1
2
3 3
Slide 31
Slide 31 text
Continue in the UI thread
1
2
3
launch(UI) {
...
}
UI
UI
UI
Slide 32
Slide 32 text
Custom executor
launch(CustomContext) {
...
}
You can launch coroutine
in the custom executor
Slide 33
Slide 33 text
fun processImage() = async(UI) {
val deferred = loadImageAsync()
// do other work
val image = deferred.await()
showImage(image)
}
Suspension might not happen
if the result is already available
processImage
loadImageAsync
await
1
2
processImage
loadImageAsync
Slide 34
Slide 34 text
fun overlay(first: Image, second: Image): Image
fun overlayAsync() = async(CommonPool) {
val first = loadImageAsync("green")
val second = loadImageAsync("red")
overlay(first.await(), second.await())
}
Image overlay: two asynchronous
computations
Slide 35
Slide 35 text
fun overlayAsync() = async(CommonPool) {
val first = loadImageAsync("green")
val second = loadImageAsync("red")
overlay(first.await(), second.await())
}
button.onClick {
launch(UI) {
val image = overlayAsync().await()
showImage(image)
}
}
Image overlay
Slide 36
Slide 36 text
Common questions
Slide 37
Slide 37 text
Q: What about handling errors
(exceptions)?
A: await rethrows the exception, so
regular try/catch works.
Q: Can I cancel the coroutine?
A: Yes (if coroutine is cancellable).
Slide 40
Slide 40 text
val job = async(CommonPool) {
while (isActive) {
...
}
}
job.cancel()
Check cancellation explicitly
in computation code
Slide 41
Slide 41 text
Library suspend functions like
await, delay check for cancellation
val job = async(CommonPool) {
delay(1000)
task.await()
}
job.cancel()
Slide 42
Slide 42 text
You can run the code without
cancellation
val job = launch(CommonPool) {
try {
...
} finally {
run(NonCancellable) {
// this code isn't cancelled
}
}
}
job.cancel()
Slide 43
Slide 43 text
Q: Can I define my custom
suspend functions?
A: Yes.
Slide 44
Slide 44 text
suspend fun login(login: String): UserID
suspend fun loadUserData(userID: UserID): UserData
suspend fun loadImage(id: String): Image
Functions that can be suspended
Slide 45
Slide 45 text
suspend fun showUserInfo(name: String) {
val userID = login(name)
val data = loadUserData(userID)
val image = async(CommonPool) {
loadImage(userData.imageID)
}
launch(UI) {
showData(data)
showImage(image.await())
}
}
Using suspend functions
Slide 46
Slide 46 text
Q: Where can I call suspend functions?
A: Inside other suspend functions and
inside async/launch (in fact: inside
suspend lambdas).
Slide 47
Slide 47 text
fun launch(
context: CoroutineContext,
block: suspend CoroutineScope.() -> Unit
): Job
fun async(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
) : Deferred
suspend lambdas
Slide 48
Slide 48 text
Implementation details
Slide 49
Slide 49 text
suspend fun foo(): Int
suspend fun foo(continuation: Continuation): Int
Hidden parameter: continuation
Slide 50
Slide 50 text
suspend fun foo(): Int
fun fooAsync(): CompletableFuture =
future { foo() }
fun fooAsync(): Single =
rxSingle(CommonPool) { foo() }
To call suspend foo from Java
wrap it into fooAsync
if you have Java 8
if you have RxJava
Slide 51
Slide 51 text
Coroutine body is
compiled to a
state machine
1
2
3
4
…
state 1
state 2
Slide 52
Slide 52 text
Bonus: yield
Slide 53
Slide 53 text
fun load(s: String) = run { println("loading $s"); s }
val seq = buildSequence {
yield(load("first"))
yield(load("second"))
}
for (s in seq) {
println("processing $s")
}
loading first
processing first
loading second
processing second
yield when required
Slide 54
Slide 54 text
coroutines
async/await
Language
Library
channels
actors
kotlinx.coroutines
yield
Slide 55
Slide 55 text
kotlinx.coroutines
• https://github.com/Kotlin/kotlinx.coroutines/
• Guide to kotlinx.coroutines by example
• by Roman Elizarov (@relizarov)