COROUTINE_SUSPENDED 和 Kotlin 中的 suspendCoroutineOrReturn
COROUTINE_SUSPENDED and suspendCoroutineOrReturn in Kotlin
kotlin 中协程的思想是抽象挂起和回调的概念并编写简单的顺序代码。你永远不用担心协程是否被挂起,类似于线程。
suspendCoroutineOrReturn
和 COROUTINE_SUSPENDED
的用途是什么?您会在什么情况下使用它们?
最近在 1.1 中引入了 suspendCoroutineOrReturn
和 COROUTINE_SUSPENDED
内部函数,以解决特定的堆栈溢出问题。
这是一个例子:
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
并没有真正挂起,但 return 立即得到结果(例如缓存)的情况。
在 Kotlin 中编译协程的状态机将进行以下调用:
problem$stateMachine
、await
、CompletableFuture.whenComplete
、await$lambda
、ContinuationImpl.resume
、problem$stateMachine
、await
、...
本质上,没有任何东西被挂起,状态机在同一个执行线程中一次又一次地调用自身,最终以 WhosebugError
.
结束
一个建议的解决方案是允许await
return一个特殊的标记(COROUTINE_SUSPENDED
)来区分协程是否真的挂起,这样状态机就可以避免堆栈溢出。
接下来, suspendCoroutineOrReturn
用于控制协程执行。这是它的声明:
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T
请注意,它收到一个带有延续的块。基本上它是一种访问 Continuation
实例的方法,
通常隐藏起来,只在编译期间出现。该块还允许 return 任何值或 COROUTINE_SUSPENDED
.
由于这一切看起来相当复杂,Kotlin 试图将其隐藏起来并建议只使用 suspendCoroutine
函数,它会在内部为您完成上述所有工作。
这是避免 WhosebugError
的正确 await
实现(旁注:await
在 Kotlin lib 中提供,它实际上是一个扩展函数,但对于本次讨论来说并不那么重要)
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
和 return COROUTINE_SUSPENDED
。
kotlin 中协程的思想是抽象挂起和回调的概念并编写简单的顺序代码。你永远不用担心协程是否被挂起,类似于线程。
suspendCoroutineOrReturn
和 COROUTINE_SUSPENDED
的用途是什么?您会在什么情况下使用它们?
最近在 1.1 中引入了 suspendCoroutineOrReturn
和 COROUTINE_SUSPENDED
内部函数,以解决特定的堆栈溢出问题。
这是一个例子:
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
并没有真正挂起,但 return 立即得到结果(例如缓存)的情况。
在 Kotlin 中编译协程的状态机将进行以下调用:
problem$stateMachine
、await
、CompletableFuture.whenComplete
、await$lambda
、ContinuationImpl.resume
、problem$stateMachine
、await
、...
本质上,没有任何东西被挂起,状态机在同一个执行线程中一次又一次地调用自身,最终以 WhosebugError
.
一个建议的解决方案是允许await
return一个特殊的标记(COROUTINE_SUSPENDED
)来区分协程是否真的挂起,这样状态机就可以避免堆栈溢出。
接下来, suspendCoroutineOrReturn
用于控制协程执行。这是它的声明:
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T
请注意,它收到一个带有延续的块。基本上它是一种访问 Continuation
实例的方法,
通常隐藏起来,只在编译期间出现。该块还允许 return 任何值或 COROUTINE_SUSPENDED
.
由于这一切看起来相当复杂,Kotlin 试图将其隐藏起来并建议只使用 suspendCoroutine
函数,它会在内部为您完成上述所有工作。
这是避免 WhosebugError
的正确 await
实现(旁注:await
在 Kotlin lib 中提供,它实际上是一个扩展函数,但对于本次讨论来说并不那么重要)
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
和 return COROUTINE_SUSPENDED
。