jvm - Kotlin 中的 COROUTINE_SUSPENDED 和 suspendCoroutineOrReturn

标签 jvm kotlin coroutine suspend

kotlin 中协程的想法是抽象暂停和回调的概念并编写简单的顺序代码。你永远不需要担心协程是否被挂起,类似于线程。
suspendCoroutineOrReturn的目的是什么和 COROUTINE_SUSPENDED在什么情况下你会使用它们?

最佳答案

suspendCoroutineOrReturnCOROUTINE_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/

相关文章:

android - 如何取消withContext中运行的协程?

jvm - jscv : Cannot locate JVM library file

java - Sun 在 Ubuntu 64 位上的 JVM 堆大小限制

android - 使用Kotlin Coroutines和Realm执行数据库写入会导致UI卡住

android - 升级okhttp后出现BootstrapMethodError

kotlin - JetpackCompose 1.0.0-alpha11 中 RememberRippleInduction 的替代品是什么?

Python 协程不与 time.sleep() 同时运行?

java - 如何使用特殊字符和空格设置 intellij 服务器 jvm 参数

java - OSX 上 JVM 的 Zombie http.proxyHost 设置

android - Kotlin - 在 Android 中转换 Singleton DatabaseController 的最佳方式