通常,我正在使用标准的kotlin-jdk8库从Java *future
API世界跳入Kotlin的suspend
天堂。
它对我来说非常有用,直到遇到Neo4J游标API,在完成阶段我无法完成.await()
,因为它立即开始将数百万条记录提取到内存中。
科特琳的方式对我不起作用,像这样:
suspend fun query() {
driver.session().use { session ->
val cursor: StatementResultCursor = session.readTransactionAsync {
it.runAsync("query ...", params)
}.await() // HERE WE DIE WITH OOM
var record = cursor.nextAsync().await()
while (record != null) {
val node = record.get("node")
mySuspendProcessingFunction(node)
}
}
}
与此同时,Java API运作良好,我们一一读取记录:
suspend fun query() {
session.readTransactionAsync { transaction ->
transaction.runAsync("query ...", params).thenCompose { cursor ->
cursor.forEachAsync { record ->
runBlocking { // BUT I NEED TO DO RUN BLOCKING HERE :(
val node = record.get("node")
mySuspendProcessingFunction(node)
}
}
}
}.thenCompose {
session.closeAsync()
}.await()
}
第二个选项对我有用,但是非常丑陋-绝对不是Kotlin方式,更重要的是,我需要使用runBlocking(但是这些整个块都在suspend函数中执行)
我在做什么错?有更好的方法吗?
UPD 尝试使用新的Flow()功能进行此练习,不幸的是结果是相同的:
suspend fun query() {
session.readTransactionAsync { transaction ->
transaction.runAsync(query, params).thenApply { cursor ->
cursor.asFlow().onEach { record ->
val node = record.get("node")
mySuspendProcessingFunction(node)
}
}
}.thenCompose {
session.closeAsync()
}.await()
}
fun StatementResultCursor.asFlow() = flow {
do {
val record = nextAsync().await()
if (record != null) emit(record)
} while (record != null)
}