



















This post is written to dictate some opinionated explanation that dispels my confusion to Kotlin coroutines during learning.
suspend keyword colors a functionThe suspend keyword in Kotlin colors a function, just like the async keyword in Javascript and Python, to inform the compiler that it might execute some asynchronous tasks.
suspending functions, such as the delay() function, must only be invoked within another suspending function.
suspend fun foo() {
delay(1000)
}
fun bar() {
delay(1000)
}
async def foo():
await asyncio.sleep(1)
def bar():
await asyncio.sleep(1)
If two suspending functions fun1() and fun2() are invoked one followed with another, their invocations are sequentialized, i.e., only after fun1() finished will fun2() be started. This is in contrast with Javascript or Python, where async-functions must be explicitly await-ed to sequentialize.
suspend fun fun1() { delay(1000) }
suspend fun fun2() { delay(2000) }
suspend fun foo() {
fun1()
fun2()
}
async def fun1(): await asyncio.sleep(1)
async def fun2(): await asyncio.sleep(2)
async def foo():
fun1()
fun2()
In both of the preceding codes, fun1() and fun2() are invoked without additional syntax constructs. In Kotlin the invocations are sequential by default, and thus foo() will return in 3 seconds. In Python, the coroutines created are leaked without any execution, causing foo() to return immediately, and hopefully you will get a RuntimeWarning: coroutine 'fun1' was never awaited as alert. To equalize them, the Python version should use explicit await:
suspend fun fun1() { delay(1000) }
suspend fun fun2() { delay(2000) }
suspend fun foo() {
fun1()
fun2()
}
async def fun1(): await asyncio.sleep(1)
async def fun2(): await asyncio.sleep(2)
async def foo():
await fun1()
await fun2()
Such difference between Kotlin and other languages prevents the case of developers forgetting to write await and leaking coroutines, which is a foundation of ergonomic structural concurrency.
In Kotlin, coroutine builders such as launch() or async() must be invoked within a coroutine scope, since they are effectively extension methods of class CoroutineScope. However, a suspend function does not essentially form a coroutine scope, which means the following code is invalid:
suspend fun foo() {
launch { delay(1000) }
}
Instead, one should wrap the function with a coroutineScope call to make use of the extensions:
suspend fun foo() {
suspend fun foo() = coroutineScope {
launch { delay(1000) }
}
suspend fun foo() {
launch { delay(1000) }
}
suspend fun foo() = coroutineScope {
launch { delay(1000) }
}
Apart from coroutineScope(), other functions like launch(), async() or runBlocking() also create coroutine scopes.
Coroutine scopes are hierarchical. When calling .launch() or .async() from a outer scope, a child scope is inherited and created from it, implicitly forming a tree-like invocation structure.
fun main(): Unit = runBlocking(CoroutineName("A")) {
launch(CoroutineName("B")) {
launch(CoroutineName("C")) {
delay(1000)
println(2)
}
println(1)
}.join()
launch(CoroutineName("D")) { println(3) }
}
In the above program, we explictly attributes the name of different coroutines in order to refer them crystally. The program will create a conceptual hierarchy as below
A --> B -> C
\-> D
Such hierarchy constrains the lifecycle of coroutines and therefore derives the structural concurrency. Specifically, we have –
Coroutine scopes are self-contained. A parental coroutine always waits for completion of all its children. Cancelling a parental coroutine recursively cancels all its children. The rules implies the program above would output like:
1 (after one second)
2
3
Since launch(CoroutineName("B")) {...}.join() would block until its child coroutine-C returns in one second. The self-containing property enables ergonomic cooperative job cancellation and ensures coroutines won’t be readily leaked 1.
GlobalScope.launch.Author: hsfzxjy.
Link: .
License: CC BY-NC-ND 4.0.
All rights reserved by the author.
Commercial use of this post in any form is NOT permitted.
Non-commercial use of this post should be attributed with this block of text.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。