协程范围和异步-正确的方法?

时间:2019-12-11 15:11:34

标签: kotlin jvm kotlin-coroutines

我喜欢协同例程的概念,并且在我的android项目中一直在使用。目前,我正在开发一个JVM模块,该模块将包含在Ktor项目中,并且我知道ktor支持协例程。

(找到随附的代码段)

只是想知道这是正确的方法吗? 如何在递归中使用异步?

任何您可以推荐的资源都可以帮助我掌握对例程的更深入的了解。

谢谢!

override suspend fun processInstruction(args.. ): List<Any> = coroutineScope {

 val dataWithFields = async{       
     listOfFields.fold(mutableList()){ acc,field ->
    val data = someProcess(field)
    val nested = processInstruction(...nestedField) // nested call

    acc.addAll(data)
    acc.addAll(nested)
    acc
}
}

return@coroutineScope postProcessData(dataWithFields.await())

}

1 个答案:

答案 0 :(得分:1)

如果要并行处理所有嵌套的调用,则应将它们包装在async中(async应该在循环内)。然后,在循环之后,您应该await所有结果。 (在您的代码中,您在await之后紧接着运行async,因此没有并行执行。)

例如,如果您有Element

interface Element {
    val subElements: List<Element>
    suspend fun calculateData(): SomeData
}

interface SomeData

并且您想要并行calculateData的所有subElements,您可以这样做:

suspend fun Element.calculateAllData(): List<SomeData> = coroutineScope {
    val data = async { calculateData() }
    val subData = subElements.map { sub -> async { sub.calculateAllData() } }
    return@coroutineScope listOf(data.await()) + subData.awaitAll().flatten()
}

正如您在评论部分中所述,您需要父数据来计算子数据,因此calculateAllData()首先要做的是计算父数据:

suspend fun Element.calculateAllData(
    parentData: SomeData = defaultParentData()
): List<SomeData> = coroutineScope {
    val data = calculateData(parentData)
    val subData = subElements.map { sub -> async { sub.calculateAllData(data) } }
    return@coroutineScope listOf(data) + subData.awaitAll().flatten()
}

现在您可能想知道它的运行速度有多快。考虑以下Element实现:

class ElementImpl(override val subElements: List<Element>) : Element {
    override suspend fun calculateData(parentData: SomeData): SomeData {
        delay(1000)
        return SomeData()
    }
}

fun elmOf(vararg elements: Element) = ElementImpl(listOf(*elements))

以及以下测试:

println(measureTime {
    elmOf(
        elmOf(),
        elmOf(
            elmOf(),
            elmOf(
                elmOf(),
                elmOf(),
                elmOf()
            )
        ),
        elmOf(
            elmOf(),
            elmOf()
        ),
        elmOf()
    ).calculateAllData()
})

如果不需要父数据来计算子数据,它将打印1.06s,因为在这种情况下,所有数据都是并行计算的。否则,由于元素树的高度为4,因此它将打印4.15s