给定范围内的安全异步 [英] Safe async in a given scope

查看:94
本文介绍了给定范围内的安全异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在给定的父级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 of async 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆