如何在特定位置暂停协程 [英] How to suspend a coroutine at a specific point

查看:432
本文介绍了如何在特定位置暂停协程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对以下问题感到茫然.

I am at loss with the following problem.

我有以下代码:

val parentJob: Job = Job()

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

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

I would like to be able to control, somehow akin to a semaphore, when should the coroutine suspend and when to resume exactly in the commented part of the snippet

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

I know there's suspendCancellableCoroutine but I am unsure how to use it or if it is appropriate here

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

How can this be achieved or are there any tutorials about this?

推荐答案

从回调和延续而不是线程和信号量的角度考虑协程可能会更有帮助.

It would be more helpful to think about coroutines in terms of callbacks and continuations, not threads and semaphores.

在内部,当协程被挂起时,整个suspend fun调用链都返回一个特殊的内部对象COROUTINE_SUSPENDED.因此,协程的整个执行过程只是一个函数调用,在此过程中将建立一个回调对象.此回调是 continuation ,当您调用它时,将从返回特殊COROUTINE_SUSPENDED对象的地方恢复执行.

Internally, when the coroutine is suspended, the entire chain of suspend fun calls returns with a special internal object, COROUTINE_SUSPENDED. So the whole execution of a coroutine is just a function call during which a callback object is being built up. This callback is the continuation and when you call it, execution resumes from the place which returned the special COROUTINE_SUSPENDED object.

Kotlin以连续对象作为参数运行传递给suspendCancellableCoroutine的块.因此,您应该保存该对象,并将其提供给协程外部的代码.

Kotlin runs the block you pass to suspendCancellableCoroutine with the continuation object as the parameter. So you should save this object and make it available to the code outside the coroutine.

有些代码可以帮助您理解.请注意,如果您要取消协程,则无需创建单独的父作业.您只需取消launch返回的Job实例,协程将不会在暂停后恢复.

Here's some code that may help your understanding. Note there's no need to create a separate parent job if you want to cancel the coroutine. You can just cancel the Job instance that launch returns and the coroutine will not resume after suspension.

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属性:

If you still need an explicit check (because there aren't enough suspension points on the execution path), you can just use the isActive property which is available directly to the block:

while (isActive) ...

这篇关于如何在特定位置暂停协程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆