How to join a Kotlin SupervisorJob

假装没事ソ 提交于 2021-02-09 11:59:06

问题


I am trying to process a tree of data objects. Each tree leaf is supposed to be processed through a function using a coroutine. The whole process should be done using a fixed size threadpool.

So I came up with this:

val node = an instance of WorkspaceEntry (tree structure)
val localDispatcher = newFixedThreadPoolContext(16)

fun main() {
    val job = SupervisorJob()
    val scope = CoroutineScope(localDispatcher + job)
    handleEntry(node, scope)

    runBlocking {
        job.join()
    }
}

The handleEntry method recursively launches a child job in the supervisor for each tree leaf.

The child jobs of the supervisor all complete successfully, but the join never returns. Am I understanding this wrong?

Edit: HandleEntry function

private fun handleEntry(workspaceEntry: WorkspaceEntry, scope: CoroutineScope) {
    if (workspaceEntry is FileEntry) {
        scope.launch {
            FileTypeRegistry.processFile(workspaceEntry.fileBlob)
        }
    } else {
        workspaceEntry.children.forEach { child -> handleEntry(child, scope) }
    }
}

回答1:


It seems the Job that is used to create CoroutineContext (in your case SupervisorJob) is not intended for waiting child coroutines to finish, so you can't use job.join(). I guess the main intent of that Job is to cancel child coroutines. Changing runBlocking block to the following will work:

runBlocking {
    job.children.forEach {
        it.join()
    }
}



回答2:


You have mixed two roles:

  1. the master job found in the coroutine scope that never completes on its own and is used to control the lifecycle of everything else
  2. the job corresponding to a unit of work, possibly decomposed into more child jobs

You need both, like this:

val masterJob = SupervisorJob()
val scope = CoroutineScope(localDispatcher + masterJob)

val unitOfWork = scope.launch { handleEntry(node, scope) }
runBlocking { unitOfWork.join() }

The above code doesn't really motivate the existence of the master job because you start just one child job from it, but it may make sense in a wider picture, where you have some context from which you launch many jobs, and want to be able to write

masterJob.cancel()

to cancel everything before it's done.



来源:https://stackoverflow.com/questions/53916377/how-to-join-a-kotlin-supervisorjob

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!