【问题标题】:How to find first desired result from kotlin coroutines Deferred<> (server)如何从 kotlin coroutines Deferred<> (服务器)中找到第一个想要的结果
【发布时间】:2021-03-24 16:05:48
【问题描述】:

我已经构建了一个分片库,我正在尝试向它添加协程功能。在下面的 sn-p 中,它返回它找到的第一个 true 结果:

override fun emailExists(email: String): Boolean {
    return runBlocking {
        shards
            .asyncAll { userDao.emailExists(email) }
            .map { it.await() }
            .firstOrNull { it }
    } ?: false
}

shards.asyncAll 方法是:

fun <T> async(
    shardId: Long,
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T): Deferred<T> {
    return scope.async(context, start) {
        selectShard(shardId)
        block()
    }
}
fun <T> asyncAll(
    shardIds: Collection<Long> = this.shardIds,
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T): List<Deferred<T>> {
    return shardIds.map { async(it, context, start, block) }
}

这可行,但它会查询分片以便返回,这意味着如果第一个分片需要很长时间才能返回并且它没有返回 true 但第二个分片立即返回值 @987654327 @只要第一个分片返回,我们仍在等待。有没有更好的方法来等待 Deferred&lt;&gt; 集合的值并按照它们返回的顺序处理它们,以便我可以尽早退出?

【问题讨论】:

  • 理想情况下,有一种方法可以不使用 Flow。
  • 我特别不想等待所有这些。
  • 是的,对不起。 awaitAll 适用于对第一个错误做出反应,但不适用于第一个结果。似乎没有内置的awaitAnyawaitFirst,但有this answer,您可以只专注于一个元素。

标签: multithreading kotlin kotlin-coroutines


【解决方案1】:

即使您要尽早得到答案,runBlocking 仍会等待您开始完成的所有协程然后返回。

为了运行您正在寻找的那种协程竞赛:

  1. 当第一个任务以 true 完成时,它需要存储该结果并取消所有其他任务的父作业;和
  2. 其他任务在取消时应正确中止。

不幸的是,我很确定 Kotlin 不包含执行此操作的函数,因此您必须自己做。最简单的方法可能是让每个人都抛出一个表明真实结果的异常。然后您可以在组上使用awaitAll,捕获异常并提取结果。

【讨论】:

  • 但是第一个返回的可能不是我要找的结果。
  • 只有当它你正在寻找的异常时,你才会抛出异常。我会调整文字
猜你喜欢
  • 2019-04-24
  • 2017-12-01
  • 2021-12-18
  • 1970-01-01
  • 2019-10-17
  • 2019-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多