CORUTTINE_SUSPENDED和suspendCoroutineOrReturn在Kotlin

kotlin中的协程的概念是抽象暂停和回调的概念,并写出简单的顺序代码。 如果协程暂停或不在线,则无需担心,与线程类似。

suspendCoroutineOrReturnCOROUTINE_SUSPENDED的用途是什么,在什么情况下你会使用它们?

suspendCoroutineOrReturnCOROUTINE_SUSPENDED内在函数最近在1.1中引入,以解决特定的堆栈溢出问题。 这里是一个例子:

 fun problem() = async { repeat(10_000) { await(work()) } } 

await等待完成的地方:

 suspend fun  await(f: CompletableFuture, c: Continuation): Unit { f.whenComplete { value, exception -> // <- await$lambda if (exception != null) c.resumeWithException(exception) else c.resume(value) } } 

让我们看看work没有真正挂起的情况,但立即返回结果(例如,缓存)。 在Kotlin中编译进入协程的状态机将进行如下调用: problem$stateMachineawaitCompletableFuture.whenCompleteawait$lambdaContinuationImpl.resumeproblem$stateMachineawait ,...

本质上,没有任何事情是暂停的,并且状态机一次又一次地在同一个执行线程中调用它自己,最后是StackOverflowError

建议的解决方案是允许await返回一个特殊的令牌( COROUTINE_SUSPENDED )来区分协程实际上是否挂起,这样状态机可以避免堆栈溢出。 接下来, suspendCoroutineOrReturn用来控制协程的执行。 这是它的声明:

 public inline suspend fun  suspendCoroutineOrReturn(crossinline block: (Continuation) -> Any?): T 

请注意,它会收到一个提供了延续的块。 基本上这是一种访问Continuation实例的方法,它通常隐藏起来,只在编译期间出现。 该块也被允许返回任何值或COROUTINE_SUSPENDED

由于这一切看起来相当复杂,Kotlin试图隐藏它,并建议只使用suspendCoroutine函数,它在内部完成上面提到的所有内容。 这里是正确的await实现,它避免了StackOverflowError (旁注: await在Kotlin库中发布,它实际上是一个扩展函数,但对于这个讨论并不重要)

 suspend fun  await(f: CompletableFuture): T = suspendCoroutine { c -> f.whenComplete { value, exception -> if (exception != null) c.resumeWithException(exception) else c.resume(value) } } 

但是,如果您想要接管对协程继续的精细控制,则应在每次进行外部调用时调用suspendCoroutineOrReturn并返回COROUTINE_SUSPENDED