我有一个API,它可以响应";稍后再试";。在这种情况下,我想递归地调用该函数(以自动传播取消(。
简化示例:
suspend fun loadData() {
runCatching { someApi.loadData() }
.onSuccess { response ->
if (response is Response.TryAgain) {
delay(1000)
loadData()
}
}
}
如果我理解正确的话,这段代码不应该导致StackOverflowError
(与常规的非挂起递归函数相反(。
我从Roman Elizarov的文章中得到了这个想法,但我在这里没有使用DeepRecursiveFunction
。
我为Android写了一些测试,似乎是:
suspend
函数在1000-4000左右的深度抛出StackOverflowError
(就像非暂停函数一样(- 具有悬挂点的
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
}
}
}
}