给定范围内的安全异步



我想在给定的父CoroutineScope中启动一个带有挂起函数的异步协程,以生成一个Deferred,然后可以从该范围内的任何协程使用。

如果父级的作业被取消,我希望它的作业被取消,但如果挂起函数引发异常,我需要在生成的Deferred中捕获该异常,而无需取消父范围内的同级作业。

我这样做的方式很好,但我想知道是否有比这更简单、更偶像的方法:

fun <T> callIt(scope: CoroutineScope, block: suspend () -> T) : Deferred<T> {
val result = CompletableDeferred<T>()
scope.launch {
try {
result.complete(block())
} catch (e: Throwable) {
result.completeExceptionally(e)
}
}
return result
}

我喜欢处理挂起block的异常显然是我想要的,但我不太高兴用launch构建一个async

不起作用的事情:

  • 具有异常处理程序的异步作业。async捕获其异常,但作业仍然失败并取消其父项。 正如@Rene评论的那样:async的文档说:"它在未能实施结构化并发范式时取消父作业(或外部范围(。

你可以在没有CompletableDeferred的情况下做到这一点。您需要创建一个SupervisorJob,并让CoroutineScope中的作业成为新作业的父作业。如果取消作用域,则async协程也会被取消。但是async-coroutine 内的任何异常都不会取消父作用域。

由于存在未解决的问题 https://github.com/Kotlin/kotlinx.coroutines/issues/1578 我们需要显式完成主管作业。

fun <T> callIt(scope: CoroutineScope, block: suspend () -> T): Deferred<T> {
val supervisorJob = SupervisorJob(scope.coroutineContext[Job])
val deferred = scope.async(supervisorJob) {
block()
}
deferred.invokeOnCompletion {
supervisorJob.complete()
}
return deferred
}

最新更新