如何加入Kotlin SupervisorJob

如何加入Kotlin SupervisorJob,kotlin,kotlinx.coroutines,Kotlin,Kotlinx.coroutines,我正在尝试处理数据对象树。每个树叶都应该通过一个使用协程的函数进行处理。整个过程应该使用固定大小的线程池来完成 所以我想到了这个: val node = an instance of WorkspaceEntry (tree structure) val localDispatcher = newFixedThreadPoolContext(16) fun main() { val job = SupervisorJob() val scope = CoroutineScope

我正在尝试处理数据对象树。每个树叶都应该通过一个使用协程的函数进行处理。整个过程应该使用固定大小的线程池来完成

所以我想到了这个:

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()
    }
}
handleEntry方法递归地在主管中为每个树叶启动子作业

主管的子作业都已成功完成,但联接从未返回。我理解错了吗

编辑:HandleEntry函数

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

似乎用于创建
CoroutineContext
(在您的情况下是
SupervisorJob
)的
作业
)不用于等待子coroutines完成,因此您不能使用
Job.join()
。我想这项
工作的主要目的是取消子协同程序。将
runBlocking
block更改为以下选项将起作用:

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

您混合了两个角色:

  • 在协同程序作用域中找到的主作业,它永远不会自行完成,并用于控制其他所有内容的生命周期
  • 与工作单元相对应的作业,可能分解为多个子作业
  • 两者都需要,如下所示:

    val masterJob = SupervisorJob()
    val scope = CoroutineScope(localDispatcher + masterJob)
    
    val unitOfWork = scope.launch { handleEntry(node, scope) }
    runBlocking { unitOfWork.join() }
    
    上面的代码并没有真正激发主作业的存在,因为您只从主作业开始一个子作业,但从更广泛的角度来看,它可能是有意义的,因为您有一些上下文,可以从中启动许多作业,并且希望能够编写

    masterJob.cancel()
    

    在完成之前取消所有操作。

    请为
    handleEntry
    函数添加代码。所谓“加入永不返回”,是指线程被阻止,应用程序被挂起吗?
    main
    功能未完成?是。它将无限期地等待作业完成。我检查了一下:子作业确实完成了,并且被销毁了,直到主管没有留下任何子作业为止。但是作业本身从未进入完成状态。似乎如果您
    cancel
    SupervisorJob
    它会取消其所有子项,您可以等待其子项完成,然后使用
    join
    。但当然,在每个子作业中都会出现一个可能不需要的
    取消异常
    ,如果它调用一些
    挂起
    函数,则会导致停止执行。虽然这会起作用,但我很确定,这不是预期的解决方案。join的文档明确指出,子作业也必须完成。此外,由于主管本身未分配任何作业,因此应在开始作业后立即切换到完成状态。在启动子作业和调用join()时启动作业。在开发过程中的某个时刻,存在一个名为joinChildren()的函数。但是现在它已经不存在了。但是,是的,因为我可能不理解一些完全错误的事情,所以我不得不这样做。事实上,我使用主管作业,因为我从它启动多个子作业(handleEntry递归启动更多作业)我希望他们能够在不中断整个过程的情况下独立失败,但解决方案不起作用。主作业不是无限期地阻塞,而是等待handleEntry()完成并立即切换到完成状态:join()返回。但是,handleEntry中启动的其他作业(使用scope参数)仍在运行。您是在谈论我的代码还是您的代码<代码>主作业不会等待任何事情完成,因此它不会更改状态
    unitOfWork
    将故障传播到其他协同程序,这是正确的。因此,您的情况实际上不是标准情况,因此使用
    masterJob.children.forEach{it.join()}
    的方法是正确的。好的,那么将
    masterJob
    添加到范围中有什么意义呢?
    masterJob
    是一个
    SupervisorJob
    ,这就是为什么它不会传播您的孩子协作的失败。它也是在其范围内启动的所有协同程序的收集器,因此您可以
    将它们全部加入。