簡體   English   中英

CoroutineScope 取消

[英]CoroutineScope cancelation

我完全了解suspendCoroutine 和suspendCancellableCoroutine 在我的示例中是如何工作的。 但我想知道為什么在我調用 viewScope.cancel() 之后執行println("I finished") (第 13 行 - viewscope 塊中的第二行)。 我可以在此行之前使用 isActive 標志修復它,但我不想檢查每一行。 我在那里想念什么。 我如何也可以取消 scope? 謝謝

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 :)")
}

如果我們只是調用cancel ,並不意味着協程工作就會停止。 如果您正在執行一些相對繁重的計算,例如從多個文件中讀取,則沒有什么可以自動阻止您的代碼運行。 一旦調用了job.cancel ,我們的協程就會轉到 Canceling state。

取消協程代碼需要協同

您需要確保您正在實施的所有協程工作都與取消合作,因此您需要定期或在開始任何長時間運行的工作之前檢查取消。 例如,如果您正在從磁盤讀取多個文件,則在開始讀取每個文件之前,請檢查協程是否被取消。 像這樣,您可以避免在不再需要時進行 CPU 密集型工作。

kotlinx.coroutines中的所有掛起函數都是可取消的: withContextdelay等。因此,如果您使用其中任何一個,則無需檢查取消並停止執行或拋出CancellationException 但是,如果您不使用它們,請通過檢查job.isActiveensureActive()使您的協程代碼協作

協程取消是合作的

如果您希望在協程被取消時不執行該語句,則應在println("I finished")之前檢查協程是否仍處於活動狀態,如下所示:

if (isActive)
    println("I finished")

這是為什么?

協程不保證在另一個線程上調度。 因此,雖然線程提供了中止的方法,它在運行時的系統級或用戶級實現(例如 JVM 或 ART),但無論如何都不能取消不受線程支持的協程,因為唯一可以做的就是拋出一個異常,但這會中止整個當前執行上下文(即線程),其他協程可能正在運行。
其他答案談論繁重的計算,但這顯然是錯誤的。 無論你在做什么,無論計算量是否繁重——協程都不能被強行取消; 它們的取消只是一個被取消的請求,由協程主體使用CoroutineScope屬性isActive來處理取消請求,它會得到一個 boolean 指示協程正在進行的工作是否應該繼續,如果為true 或被取消,如果false

使用 suspendCancellableCoroutine 正在按預期工作。 suspendCoroutine 不檢查 coroutineScope 的取消 state(內部使用 safeContinuation),而 suspendCancellableCoroutine 通過 CancellableContinuationImpl 檢查取消並取消恢復操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM