Why intermediate coroutine hangs up top level coroutine? - Stack Overflow

admin2025-04-21  2

Where is task to process big list of items in sequential-parallel way: split big list to chunks, process chunks one after another, process items from each chunk in parallel. Implementing this task, I encounter a problem and reduce that task to reproduce it in simplest way.

val rootScope = CoroutineScope(Dispatchers.IO)

val list: List<Int> = listOf(1,2,3,4,5)

rootScope.launch {
    val rootLocalScope = this
    log("-----> rootScope (start)")

    launch {
        val mediumLocalScope = this

        list.map {  i ->
            // 
            // Replace rootLocalScope to mediumLocalScope in SupervisorJob() and hangs up work...
            //
            launch (SupervisorJob(rootLocalScope.coroutineContext.job)) {
                log("Downloading file-$i")
                delay(1000)
            }
        }.joinAll()
        
    }.join()

    log("-----> rootScope (finish)")
}

Remark: all .join() are required, there is no right sequence of work without it.

Output is:

With SupervisorJob(rootLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
-----> rootScope (finish)

With SupervisorJob(mediumLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
*I.e. top level coroutine not reached its finish...*

So, the question: why SupervisorJob(mediumLocalScope.coroutineContext.job) not works?

Where is task to process big list of items in sequential-parallel way: split big list to chunks, process chunks one after another, process items from each chunk in parallel. Implementing this task, I encounter a problem and reduce that task to reproduce it in simplest way.

val rootScope = CoroutineScope(Dispatchers.IO)

val list: List<Int> = listOf(1,2,3,4,5)

rootScope.launch {
    val rootLocalScope = this
    log("-----> rootScope (start)")

    launch {
        val mediumLocalScope = this

        list.map {  i ->
            // 
            // Replace rootLocalScope to mediumLocalScope in SupervisorJob() and hangs up work...
            //
            launch (SupervisorJob(rootLocalScope.coroutineContext.job)) {
                log("Downloading file-$i")
                delay(1000)
            }
        }.joinAll()
        
    }.join()

    log("-----> rootScope (finish)")
}

Remark: all .join() are required, there is no right sequence of work without it.

Output is:

With SupervisorJob(rootLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
-----> rootScope (finish)

With SupervisorJob(mediumLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
*I.e. top level coroutine not reached its finish...*

So, the question: why SupervisorJob(mediumLocalScope.coroutineContext.job) not works?

Share Improve this question asked Jan 22 at 21:54 An12An12 211 silver badge3 bronze badges 1
  • 2 I think I understand the reason for the behavior, but I feel the real answer should be: remove all "strange" code bits, remove 60% of the code and keep it simple. You pass a Job to launch, which in most cases is not a very good idea and it may result with many kinds of strange behaviors. You do a lot of launches and joins and they all look unnecessary. You wrote a "strange" code, so you got a "strange" behavior. Is there any specific reason for doing the above? Couldn't you simply do: list.map { launch { ... }}.joinAll() and that's it? – broot Commented Jan 23 at 1:15
Add a comment  | 

1 Answer 1

Reset to default 0

I found on StackOverflow similar theme. Shortly: you shoud manually call .complete() on intermediate job (SupervisorJob in discussed case, but simple Job behaves the same) after .joinAll() child jobs.

转载请注明原文地址:http://anycun.com/QandA/1745226950a90476.html