我对以下问题感到困惑。
我有以下代码:
val parentJob: Job = Job()
launch(parent = parentJob) {
while (true)
{
if (!parentJob.isCompleted)
{
// I want to control suspension here
println("Resumed")
}
}
}
我希望能够以某种方式控制信号量,协程应该何时暂停以及何时在代码段的注释部分中完全恢复
我知道这里有suspendCancellableCoroutine
,但是我不确定如何使用它,或者在这里是否合适
如何实现这一目标,或者有任何有关此的教程?
答案 0 :(得分:4)
从回调和延续而不是线程和信号量的角度考虑协程会更有用。
在内部,当协程被挂起时,整个suspend fun
调用链都返回一个特殊的内部对象COROUTINE_SUSPENDED
。因此,协程的整个执行过程只是一个函数调用,在此过程中将建立一个回调对象。此回调是 continuation ,当您调用它时,将从返回特殊COROUTINE_SUSPENDED
对象的地方恢复执行。
Kotlin使用连续对象作为参数来运行传递给suspendCancellableCoroutine
的块。因此,您应该保存该对象,并将其提供给协程外部的代码。
有些代码可以帮助您理解。请注意,如果要取消协程,则无需创建单独的父作业。您只需取消Job
返回的launch
实例,协程将不会在暂停后恢复。
import kotlin.coroutines.*
import kotlinx.coroutines.*
var continuation: Continuation<String>? = null
fun main(args: Array<String>) {
val job = GlobalScope.launch(Dispatchers.Unconfined) {
while (true) {
println(suspendHere())
}
}
continuation!!.resume("Resumed first time")
continuation!!.resume("Resumed second time")
job.cancel()
continuation!!.resume("This shouldn't print")
}
suspend fun suspendHere() = suspendCancellableCoroutine<String> {
continuation = it
}
如果仍然需要显式检查(因为执行路径上没有足够的挂起点),则可以使用直接用于该块的isActive
属性:
while (isActive) ...