递归调用Kotlin suspend函数安全吗



我有一个API,它可以响应";稍后再试";。在这种情况下,我想递归地调用该函数(以自动传播取消(。

简化示例:

suspend fun loadData() {
runCatching { someApi.loadData() }
.onSuccess { response ->
if (response is Response.TryAgain) {
delay(1000)
loadData()
}
}
}

如果我理解正确的话,这段代码不应该导致StackOverflowError(与常规的非挂起递归函数相反(。

我从Roman Elizarov的文章中得到了这个想法,但我在这里没有使用DeepRecursiveFunction

我为Android写了一些测试,似乎是:

  1. suspend函数在1000-4000左右的深度抛出StackOverflowError(就像非暂停函数一样(
  2. 具有悬挂点的suspend函数(yield()delay()(允许达到1-2百万的深度,其中OutOfMemoryError发生

这种行为是在某个地方记录的,还是只是一个可能在未来发生变化的实现细节?我还没有在协同程序设计文档或协同程序指南中找到答案,也没有在SO.上找到答案

总的来说,如果呼叫深度远低于一百万,那么使用这种模式是个好主意吗?有更好的可取消解决方案吗?

如果tailrec优化不适用于您的情况,您可以手动将递归函数转换为while循环:

suspend fun loadData() {
var getResponse = false
while (!getResponse) {
runCatching { someApi.loadData() }
.onSuccess { response ->
if (response is Response.TryAgain) {
delay(1000)
} else {
getResponse = true
}
}
}    
}

最新更新