【问题标题】:COROUTINE_SUSPENDED and suspendCoroutineOrReturn in KotlinKotlin 中的 COROUTINE_SUSPENDED 和 suspendCoroutineOrReturn
【发布时间】:2018-02-16 14:03:50
【问题描述】:

kotlin 中协程的想法是抽象暂停和回调的概念并编写简单的顺序代码。你永远不用担心协程是否被挂起,类似于线程。

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

【问题讨论】:

    标签: jvm kotlin coroutine suspend


    【解决方案1】:

    最近在 1.1 中引入了 suspendCoroutineOrReturnCOROUTINE_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 并没有真正挂起,而是立即返回结果(例如,缓存)的情况。 在 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
    

    请注意,它接收一个带有延续的块。基本上这是一种访问Continuation 实例的方法, 它通常被隐藏起来,只在编译过程中出现。该块也可以返回任何值或COROUTINE_SUSPENDED

    由于这一切看起来相当复杂,Kotlin 试图将其隐藏起来,并建议仅使用 suspendCoroutine 函数,它在内部为您完成上述所有工作。 这是正确的await 实现,它避免了StackOverflowError(旁注: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 并返回 COROUTINE_SUSPENDED

    【讨论】:

      猜你喜欢
      • 2016-10-20
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 2018-06-07
      • 2018-09-07
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多