在Kotlin协同程序中暂停function是什么意思
我正在阅读Kotlin Coroutine,知道它是基于suspend
function的。 但suspend
是什么意思?
协程或函数被暂停?
从https://kotlinlang.org/docs/reference/coroutines.html
基本上,协程是可以暂停而不阻塞线程的计算
我听到有人经常说“暂停function”。 但是我认为是因为等待函数完成而被暂停的协程? “挂起”通常意味着“停止运行”,在这种情况下,协程是空闲的。
🤔我们应该说协程暂停了吗?
哪个协程暂停?
从https://kotlinlang.org/docs/reference/coroutines.html
为了继续这个比喻,await()可以是一个挂起函数(因此也可以从async {}块中调用)暂停一个协程,直到某个计算完成并返回结果:
async { // Here I call it the outer async coroutine ... // Here I call computation the inner coroutine val result = computation.await() ... }
🤔它说“暂停一个协程,直到一些计算完成”,但协程就像一个轻量级的线程。 所以如果协程暂停,那么计算如何完成呢?
我们看到await
被调用computation
,所以它可能是async
,返回Deferred
,这意味着它可以启动另一个协程
fun computation(): Deferred { return async { true } }
🤔引用说暂停协程 。 是指suspend
外部async
协程,还是suspend
内部computation
协程?
suspend
是指在外部async
协程为内部computation
协程完成等候( await
)完成时,它(外部async
协程)空闲(因此名称暂停)并将线程返回到线程池,并且当子computation
协程完成时,它(外部async
协程)醒来,从池中取出另一个线程并继续?
我提到这个线程的原因是因为https://kotlinlang.org/docs/tutorials/coroutines-basic-jvm.html
线程在协程正在等待时返回到池中,等待完成后,协程将在池中的空闲线程上恢复
作为一个学习工具,我建议你通过这个代码,它揭示了所有的便利构造,如async
的基本机制:
import kotlinx.coroutines.experimental.Unconfined import kotlinx.coroutines.experimental.launch import kotlin.coroutines.experimental.Continuation import kotlin.coroutines.experimental.suspendCoroutine var continuation: Continuation? = null fun main(args: Array) { launch(Unconfined) { val a = a() println("Result is $a") } 10.downTo(0).forEach { continuation!!.resume(it) } } suspend fun a(): Int { return b() } suspend fun b(): Int { while (true) { val i = suspendCoroutine { cont -> continuation = cont } if (i == 0) { return 0 } } }
Unconfined
协程上下文基本上消除了协程上下文的魔力:你只要开始执行launch
块内的代码。 会发生什么如下:
- 评估
val a = a()
- 这链接到
b()
,到达suspendCoroutine
。 - 函数
b()
执行传递给suspendCoroutine
的块,然后返回一个特殊的COROUTINE_SUSPENDED
值。 这个值通过Kotlin编程模型是不可观测的,但这正是编译的Java方法所做的。 - 函数
a()
,看到这个返回值,本身也返回它。 -
launch
块执行相同的操作,现在控件在launch
调用之后返回到这一行:10.downTo(0)...
请注意,在这一点上,你有相同的效果,如果launch
块内的代码和你的fun main
代码并发执行。 这只是发生在一个本地线程上,所以launch
块被“暂停”。
现在,在forEach
循环代码中,程序读取b()
函数编写的continuation
,并以10
的值resumes
。 resume()
以这种方式实现,就好像suspendCoroutine
调用返回的值一样。它被赋值给i
并且被检查为0
。 如果它不为零,那么while (true)
循环在b()
内部继续,再次到达suspendCoroutine
,在这一点你的resume()
调用返回,现在你通过forEach()
另一个循环步骤。 这继续下去,直到最后你恢复0
,然后println
语句运行,程序完成。
上面的分析应该给你一个重要的直觉,即“暂停协程”意味着将控制返回到最内层的launch
调用(或者更一般地说, 协程生成器 )。
协同工作环境的存在使得这个推理不太清晰,因为他们中的大多数立即提交你的代码到另一个线程。 在这种情况下,上述故事发生在另一个线程中,并且协程上下文也管理continuation
对象,以便在返回值可用时继续它。