给定范围内的安全异步 [英] Safe async in a given scope
问题描述
我想在给定的父级CoroutineScope
中使用挂起功能启动异步协程,以产生一个Deferred
,然后可以在该范围内的任何协程中使用它.
I want to start an async coroutine with a suspending function in a given parent CoroutineScope
, to produce a Deferred
that might then be used from any coroutine in that scope.
如果父级作业被取消,我希望取消其作业,但是如果挂起函数引发异常,则需要在结果Deferred
中捕获的异常而不取消父级作用域中的同级作业.
I would like its job to be cancelled if the parent's job is cancelled, but if the suspending function throws an exception, I need that captured in the resulting Deferred
without cancelling sibling jobs in the parent scope.
我的工作方式很好,但是我想知道是否有比这更简单,更富于神志的方式:
The way I'm doing it works fine, but I'm wondering if there's a simpler, more idomatic way than this:
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
I like that the handling of exceptions from the suspending block
is obviously what I want, but I'm not too happy about building an async
out of launch
不起作用的东西:
- 带有异常处理程序的异步作业.
async
捕获其异常,但是作业仍然失败并取消其父项.正如@Rene所说:async
的文档说:由于未能执行结构化并发范例,它取消了父作业(或外部作用域)."
- An async job with an exception handler.
async
catches its exceptions, but the job still fails and cancels its parent. As @Rene commented: The documentation ofasync
says: " it cancels the parent job (or outer scope) on failure to enforce structured concurrency paradigm.".
推荐答案
您可以在没有CompletableDeferred
的情况下进行操作.您需要创建一个 CoroutineScope
中的作业作为新作业的父项.如果取消了范围,则async
-协程也将被取消.但是async
-协程内部的任何异常都不会取消父作用域.
You can do it without a CompletableDeferred
. You need to create an SupervisorJob
and let the job from the CoroutineScope
be the parent of the new job. If the scope is cancelled the async
-coroutine is cancelled as well. But no exception inside the async
-coroutine will cancel the parent scope.
由于存在未解决的问题 https://github.com/Kotlin/kotlinx. coroutines/issues/1578 ,我们需要明确完成SupervisorJob.
Because of an open issue https://github.com/Kotlin/kotlinx.coroutines/issues/1578 we need to explicitly complete the SupervisorJob.
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
}
这篇关于给定范围内的安全异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!