我喜欢协同例程的概念,并且在我的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())
}
答案 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
。