简体   繁体   中英

CoroutineScope with SupervisorJob vs supervisorScope

Recently I've been learning coroutines in detail, as I understand SupervisorJob() gives us opportunity to not cancel all children if one of the children of coroutine is cancelled due to some reason.

It is said that coroutines started with coroutineScope will cancel all children if one fails, but the ones started with supervisorScope will only cancel the child which is failed

I wonder if I could change behaviour of CoroutineScope by adding SupervisorJob as CoroutineContext to it, but I couldn't get expected behaviour which is the thing I don't get

Expected behaviour - getData1() and getData3() result gets printed *

Actual: - getData2() cancels all coroutine

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

You are not launching the three inner coroutines in customScope . You're launching them in the scope of the launched outer coroutine (by using implicit this to launch them). If you launch them from that custom scope that has a SupervisorJob, then it should work:

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

the SupervisorJob expected behaviour, happens when we call it with the lunch/async from the root scope.

val job1 =rootscope.lunch{}
val job2 =rootscope.lunch{}
val job3 =rootscope.lunch{}

if one of these jobs failed, it will not affect others, However if we use it as a child its acts like a Job() like your example .

but what if i need child's coroutines behave as "if it lunched from a root scope"? . like your example, then supervisorScope appear to solve this problem, if u use:

      customScope.launch {
        supervisorScope {
            launch {

                throw Exception()
            }
            launch {
                println("hjkhjk 111")
            }
            launch {
                println("hjkhjk 222")
            }
        }
    }.join()

then every child coroutines runs as rootScope.lunch{...}, and your problem will be solved

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM