kotlin 中协程的想法是抽象暂停和回调的概念并编写简单的顺序代码。你永远不需要担心协程是否被挂起,类似于线程。suspendCoroutineOrReturn
的目的是什么和 COROUTINE_SUSPENDED
在什么情况下你会使用它们?
最佳答案
suspendCoroutineOrReturn
和 COROUTINE_SUSPENDED
最近在 1.1 中引入了内在函数,以解决特定的堆栈溢出问题。
这是一个例子:
fun problem() = async {
repeat(10_000) {
await(work())
}
}
在哪里
await
只是等待完成:suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit {
f.whenComplete { value, exception -> // <- await$lambda
if (exception != null) c.resumeWithException(exception) else
c.resume(value)
}
}
我们来看看
work
时的情况并没有真正挂起,而是立即返回结果(例如,缓存)。在 Kotlin 中编译协程的状态机将进行以下调用:
problem$stateMachine
, await
, CompletableFuture.whenComplete
, await$lambda
, ContinuationImpl.resume
, problem$stateMachine
, await
, ...本质上,没有任何东西被挂起,状态机在同一个执行线程中一次又一次地调用自己,最终以
StackOverflowError
结束。 .建议的解决方案是允许
await
返回一个特殊的标记(COROUTINE_SUSPENDED
)来区分协程是否真的挂起,这样状态机就可以避免堆栈溢出。接下来,
suspendCoroutineOrReturn
是否可以控制协程执行。这是它的声明:public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T
请注意,它接收一个带有延续的 block 。基本上这是一种访问
Continuation
的方法实例,它通常被隐藏起来,只在编译过程中出现。该 block 也可以返回任何值或
COROUTINE_SUSPENDED
.由于这一切看起来相当复杂,Kotlin 试图将其隐藏并建议仅使用
suspendCoroutine
函数,它在内部为您完成上述所有工作。这是正确的
await
避免 StackOverflowError
的实现(旁注:await
是在 Kotlin 库中提供的,它实际上是一个扩展函数,但对于本次讨论并不那么重要)suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutine { c ->
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception) else
c.resume(value)
}
}
但是,如果您想要接管对协程延续的精细控制,您应该调用
suspendCoroutineOrReturn
并返回 COROUTINE_SUSPENDED
每当有外部调用时。
关于jvm - Kotlin 中的 COROUTINE_SUSPENDED 和 suspendCoroutineOrReturn,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46103024/