如何在特定位置暂停协程

IS1*_*_SO 3 kotlin kotlin-coroutines

我不知所措,以下问题。

我有以下代码:

val parentJob: Job = Job()

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

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

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

如何做到这一点,或者有任何有关此的教程?

Mar*_*nik 5

从回调和延续而不是线程和信号量的角度考虑协程会更有用。

在内部,当协程被挂起时,整个suspend fun调用链将返回一个特殊的内部对象COROUTINE_SUSPENDED。因此,协程的整个执行过程只是一个函数调用,在此过程中将建立一个回调对象。此回调是继续,当您调用它时,将从返回特殊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
}
Run Code Online (Sandbox Code Playgroud)

如果仍然需要显式检查(因为执行路径上没有足够的挂起点),则可以使用isActive直接可用于块的属性:

while (isActive) ...
Run Code Online (Sandbox Code Playgroud)