【问题标题】:CoroutineScope cancelationCoroutineScope 取消
【发布时间】:2020-12-10 17:44:44
【问题描述】:

我完全了解suspendCoroutine 和suspendCancellableCoroutine 在我的示例中是如何工作的。但我想知道为什么在我调用 viewScope.cancel() 之后执行 println("I finished") (第 13 行 - viewscope 块中的第二行)。我可以在此行之前使用 isActive 标志修复它,但我不想检查每一行。我在那里想念什么。我如何也可以取消范围?谢谢

import kotlinx.coroutines.*
import java.lang.Exception
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

fun main() {
    val parentJob = Job()
    val viewScope = CoroutineScope(Dispatchers.IO + parentJob)

    viewScope.launch {
        println(tryMe())
        println("I finished")
    }
    Thread.sleep(2000)
    viewScope.cancel()
    Thread.sleep(10000)
}

suspend fun tryMe() = suspendCoroutine<String> {
    println("I started working")
    Thread.sleep(6000)
    println("Im still working :O")
    it.resume("I returned object at the end :)")
}

suspend fun tryMe2() = suspendCancellableCoroutine<String> {
    println("I started working")
    Thread.sleep(6000)
    println("Im still working :O")
    it.resume("I returned object at the end :)")
}

suspend fun tryMe3() = suspendCancellableCoroutine<String> {
    it.invokeOnCancellation { println("I canceled did you heard that ?") }
    println("I started working")
    Thread.sleep(6000)
    if (it.isActive)
        println("Im still working :O")
    it.resume("I returned object at the end :)")
}

【问题讨论】:

  • 不要使用 Thread.sleep()。你阻塞了整个线程和其中的协程。请改用 delay()。
  • 协程仅在挂起操作期间或明确告知时检查取消。 Thread.sleep 没有。
  • Thread.sleep 仅用于测试目的,我无法在 suspendCancellableCoroutine 中调用延迟函数。

标签: android kotlin coroutine


【解决方案1】:

如果我们只是调用cancel,并不意味着协程工作就会停止。如果您正在执行一些相对繁重的计算,例如从多个文件中读取,则没有什么可以自动阻止您的代码运行。一旦job.cancel 被调用,我们的协程就会进入Canceling 状态。

协程代码的取消需要协同

您需要确保您正在实施的所有协程工作都与取消协同工作,因此您需要定期或在开始任何长时间运行的工作之前检查取消。例如,如果您正在从磁盘读取多个文件,则在开始读取每个文件之前,请检查协程是否被取消。像这样,您可以避免在不再需要时执行 CPU 密集型工作。

kotlinx.coroutines 中的所有挂起函数都是可取消的:withContextdelay 等。因此,如果您使用其中任何一个,则无需检查取消并停止执行或抛出 CancellationException。但是,如果您不使用它们,请通过检查 job.isActiveensureActive() 来使您的协程代码协作

【讨论】:

    【解决方案2】:

    使用 suspendCancellableCoroutine 可以正常工作。 suspendCoroutine 不检查 coroutineScope 的取消状态(内部使用 safeContinuation),而 suspendCancellableCoroutine 通过 CancellableContinuationImpl 检查取消并取消恢复操作。

    【讨论】:

      【解决方案3】:

      协程取消是合作的

      你应该在println("I finished")之前检查协程是否仍然活动,如果你希望在协程被取消的情况下不执行该语句,如下所示:

      if (isActive)
          println("I finished")
      

      为什么会这样?

      协程不保证在另一个线程上调度。因此,虽然线程提供了中止的方法,它在运行时的系统级或用户级实现(例如 JVM 或 ART),但无论如何都不能取消不受线程支持的协程,因为唯一可以做的就是抛出一个异常,但这会中止整个当前执行上下文(即线程),其他协程可能正在其中运行。
      其他答案谈论繁重的计算,但这显然是错误的. 无论你在做什么,无论是否计算量大——协程都不能被强行取消;它们的取消只是一个被取消的请求,由协程主体使用CoroutineScope 属性isActive 处理取消请求,如果true,它会获取一个布尔值,指示协程正在进行的工作是否应该继续;或者被取消,如果false

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-13
        • 1970-01-01
        • 2021-10-18
        • 2020-01-21
        • 1970-01-01
        • 2020-04-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多