Coroutine Continuation 在内部是如何工作的?

How does a Coroutine Continuation internally work?

我已经使用协程几个星期了,有时很难理解线程并发和协程并发之间真正的工作区别。

挂起函数在内部是如何工作的?继续块如何帮助在暂停后恢复计算。 协程中代码行的顺序计算如何不阻塞线程?它比线程并发性好在哪里?

原始设计文档 https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md 中解释了内部工作原理,其中有一节关于 "Implementation Details"。

How suspend functions works internally?

简而言之,在 Java 平台上,一个 suspend fun 编译成与普通函数截然不同的字节码。它接收一个隐藏的额外参数(continuation),创建自己的 continuation 对象,并且函数的整个主体(大约)实现为一个大的 switch 语句,允许函数跳转到主体的中间恢复时。

suspend fun 挂起时,底层 Java 方法实际上是 return。 return 值是一个特殊的 COROUTINE_SUSPENDED 单例对象,框架知道如何解释它。 suspend fun 本身有责任将延续对象保存在函数结果准备就绪时可以访问的地方。

official documentation 对这些细节有很好的深入描述。

How is continuation block helping in resuming the computation after suspension.

这与我上面所说的有关,suspend fun 本身负责确保稍后恢复。它必须在函数 suspendCoroutineOrReturn 提供的块内执行此操作。用户代码不会直接调用它,而是更高级的类似物suspendCoroutinesuspendCancellableCoroutine。这些接管了在适当线程上恢复协程的关注,开发人员仅负责确保 continuation.resume() 在结果可用时被调用。这通常发生在您传递给异步调用的回调中。

您可以研究 this answer,它试图在一个独立的示例中解释挂起-恢复机制。

How is sequential computation of the line of code inside coroutine not blocking the thread?

因为它实际上是从函数编译成 returning,然后通过跳转到函数体的中间来恢复。

and how is it better than thread concurrency?

本机线程是需要时间来创建和销毁的重量级资源。协程重量更轻,因此您可以更快地启动更多协程。