The document provides an in-depth review of coroutines in Kotlin, discussing various styles and techniques including direct style, continuation-passing style, and reactive programming. It highlights the benefits of coroutines, such as lightweight concurrency, and outlines how they can enhance asynchronous programming in Kotlin. The document also covers coroutine builders, exception handling, and integration with other libraries, while stressing Kotlin's experimental status and the need for feedback from the community.
Experimental status
Since Kotlin1.1
-Xcoroutines=enable
kotlin.coroutines.experimental -> kotlin.coroutines (1.3)
Experimental != unstable
Can and should be used in production
14.
Experimental status
New styleof programming
The design is not final and expected to change
JetBrains still collects information and feedbacks
Backwards compatibility guaranteed
Labels
suspend fun postItem(item:Item) {
// LABEL 0
val token = prepareToken()
// LABEL 1
val post = submitPost(token, item)
// LABEL 2
processPost(post)
}
29.
Labels
suspend fun postItem(item:Item) {
switch(label) {
case 0:
val token = prepareToken()
case 1:
val post = submitPost(token, item)
case 2:
processPost(post)
}
}
30.
State
suspend fun postItem(item:Item) {
val stateMachine = object: CoroutineImpl {…}
switch(stateMachine.label) {
case 0:
val token = prepareToken()
case 1:
val post = submitPost(token, item)
case 2:
processPost(post)
}
}
31.
CPS Transform
fun postItem(item:Item, cont: Continuation) {
val stateMachine = object: CoroutineImpl {…}
switch(stateMachine.label) {
case 0:
val token = prepareToken(stateMachine)
case 1:
val post = submitPost(token, item, stateMachine)
case 2:
processPost(post)
}
}
32.
Save state
fun postItem(item:Item, cont: Continuation) {
val stateMachine = object: CoroutineImpl {…}
switch(stateMachine.label) {
case 0:
stateMachine.item = item
stateMachine.label = 1
prepareToken(stateMachine)
case 1:
…
}
}
33.
Callback
fun postItem(item: Item,cont: Continuation) {
val stateMachine = cont as? ThisSM ?: object: ThisSM {
fun resume(…) {
postItem(null, this)
}
}
switch(stateMachine.label) {
case 0:
….
}
}
34.
Restore state andcontinue
fun postItem(item: Item, cont: Continuation) {
…
case 0:
stateMachine.item = item
stateMachine.label = 1
prepareToken(stateMachine)
case 1:
val item = stateMachine.item
val token = stateMachine.result
stateMachine.label = 2
submitPost(token, item, stateMachine)
case 2:
…
async/await
// C# way
asyncTask ProcessImage(String url)
{
var image = await LoadImage(url);
imageCache.Add(image);
}
// Kotlin way
suspend fun processImage(url: String) {
val image = loadImageAsync(url).await()
imageCache.add(image)
}
46.
Not idiomatic way
funloadImageAsync(url: String): Deferred<Image> = async { TODO() }
suspend fun processImage(url: String) {
val image = loadImageAsync(url).await()
imageCache.add(image)
}
Don’t define async functions
in the first place
47.
Idiomatic way
suspend funloadImage(url: String): Image = TODO()
suspend fun processImage(url: String) {
val image = async { loadImage(url) }.await()
imageCache.add(image)
}
Keep concurrency explicit
buildSequence {
print(“Start: ")
varprev = 1; var cur = 1
while (true) {
print(“Next")
yield(prev) // suspension point
val next = prev + cur
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
50.
buildSequence {
print(“Start: ")
varprev = 1; var cur = 1
while (true) {
print(“Next")
yield(prev) // suspension point
val next = prev + cur
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
51.
buildSequence {
print(“Start: ")
varprev = 1; var cur = 1
while (true) {
print(“Next")
yield(prev) // suspension point
val next = prev + cur
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
52.
buildSequence {
print(“Start: ")
varprev = 1; var cur = 1
while (true) {
print(“Next")
yield(prev) // suspension point
val next = prev + cur
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
53.
buildSequence {
print(“Start: ")
varprev = 1; var cur = 1
while (true) {
print(“Next")
yield(prev) // suspension point
val next = prev + cur
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