CoroutineScope 与 SupervisorJob 对比 SupervisorScope

nas*_*bov 2 android kotlin kotlin-coroutines coroutinescope

最近我一直在详细学习协程,据我所知,SupervisorJob()如果协程的子级之一由于某种原因被取消,我们有机会不取消所有子级。

据说以 开头的协程coroutineScope如果失败了,会取消所有子协程,但以 开头的协程supervisorScope只会取消失败的子协程

我想知道是否可以CoroutineScope通过添加SupervisorJobCoroutineContext 来改变行为,但我无法获得预期的行为,这是我没有得到的

预期行为 - getData1() 和 getData3() 结果被打印*

实际: - getData2() 取消所有协程

fun main() = runBlocking {

    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        println(throwable)
    }

    val customScope = CoroutineScope(SupervisorJob() + exceptionHandler)


    customScope.launch {
        launch {
            getData1().also { println(it) }
        }
        launch {
            getData2().also { println(it) }
        }
        launch {
            getData3().also { println(it) }
        }
     }.join()

}


private suspend fun getData1(): String? {
    delay(1000)
    return "data 1"
}

private suspend fun getData2(): String? {
    delay(300)
    throw RuntimeException("While getting Data 2 exception happened")
}

private suspend fun getData3(): String? {
    delay(800)
    return "data 3"
}
Run Code Online (Sandbox Code Playgroud)

小智 6

据说用 coroutineScope 启动的协程如果失败了,会取消所有子进程,但是用supervisorScope启动的协程只会取消失败的子进程

没错,但您想要做的只是创建 SupervisorScope 的 1 个子级。

在此输入图像描述

customScope.launch {
    launch {
        // some work
    }
    launch {
        throw RuntimeException()
    }
    launch {
        // some work
    }
 }
Run Code Online (Sandbox Code Playgroud)

你真正需要的是这样的东西:

在此输入图像描述

customScope.launch {
    // some work  
}
customScope.launch {
    throw RuntimeException()
}
customScope.launch {
    // some work    
}
Run Code Online (Sandbox Code Playgroud)

这就是创建新协程时亲子关系的工作方式

新协程创建自己的子 Job 实例(使用此上下文中的作业作为其父级),并将其子上下文定义为父上下文加上其作业:

要详细了解其工作原理,我建议阅读这篇文章