如何异步映射序列

chr*_*der 7 kotlin kotlinx.coroutines

我想迭代一系列对象并返回异步调用的第一个非null.

重点是执行某种可能失败的异步操作,我有一系列的后备,我想按顺序尝试,一个接一个(即懒惰/不并行).

我试图做一些类似于我所做的事情,如果它是同步调用:

// ccs: List<CurrencyConverter>
override suspend fun getExchangeRateAsync(from: String, to: String) =
  ccs.asSequence()
    .map { it.getExchangeRateAsync(from, to) }
    .firstOrNull { it != null }
    ?: throw CurrencyConverterException()
Run Code Online (Sandbox Code Playgroud)

IntelliJ抱怨:

暂停功能只能在协程体内调用

编辑:为了澄清,如果在List上映射,这可以正常工作,但我想看看我如何在序列上执行此操作.

所以我想这是因为地图lambda没有被暂停?但我不确定如何实际做到这一点.我尝试了许多不同的方法,但似乎都没有.我找不到任何例子.

如果我使用for带有异步块的循环以更加程序化的方式重写它,我可以使它工作:

override suspend fun getExchangeRateAsync(from: String, to: String) {
    for (cc in ccs) {
        var res: BigDecimal? = async {
            cc.getExchangeRateAsync(from, to)
        }.await()

        if (res != null) {
            return res
        }
    }

    throw CurrencyConverterException()
}
Run Code Online (Sandbox Code Playgroud)

小智 5

我建议用流程替换序列。Flow api 和行为与 Sequence 几乎相同,但具有暂停选项。

https://kotlinlang.org/docs/reference/coroutines/flow.html
Run Code Online (Sandbox Code Playgroud)

代码:

override suspend fun getExchangeRateAsync(from: String, to: String) =
    ccs.asFlow()
    .map { it.getExchangeRateAsync(from, to) }
    .firstOrNull { it != null }
    ?: throw CurrencyConverterException()
Run Code Online (Sandbox Code Playgroud)


Dim*_*ira 2

您收到错误,因为Sequence默认情况下是惰性的,并且它map不是内联函数,因此未定义它的范围

Sequence您可以通过创建惰性协程列表来避免使用

// ccs: List<CurrencyConverter>
suspend fun getExchangeRateAsync(from: String, to: String) =
    ccs
    .map { async(start = CoroutineStart.LAZY) { it.getExchangeRateAsync(from, to) } }
    .firstOrNull { it.await() != null }
    ?.getCompleted() ?: throw Exception()
Run Code Online (Sandbox Code Playgroud)

这不会给出任何错误并且似乎有效。但我不确定这是一种惯用的方式