如何加入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
,这就是为什么它不会传播您的孩子协作的失败。它也是在其范围内启动的所有协同程序的收集器,因此您可以将它们全部加入。