如何在特定位置暂停协程

时间:2018-07-27 21:55:42

标签: kotlin kotlin-coroutines

我对以下问题感到困惑。

我有以下代码:

val parentJob: Job = Job()

launch(parent = parentJob) {
    while (true)
    {
        if (!parentJob.isCompleted)
        {
            // I want to control suspension here
            println("Resumed")
        }
    }
}

我希望能够以某种方式控制信号量,协程应该何时暂停以及何时在代码段的注释部分中完全恢复

我知道这里有suspendCancellableCoroutine,但是我不确定如何使用它,或者在这里是否合适

如何实现这一目标,或者有任何有关此的教程?

1 个答案:

答案 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) ...