【发布时间】:2020-03-19 03:57:30
【问题描述】:
我已经使用协程工作了几个星期,有时很难理解线程并发和协程并发之间的真正工作差异。
挂起函数如何在内部工作?延续块如何帮助在暂停后恢复计算。 协程内代码行的顺序计算如何不阻塞线程?它比线程并发更好吗?
【问题讨论】:
标签: android kotlin concurrency kotlin-coroutines
我已经使用协程工作了几个星期,有时很难理解线程并发和协程并发之间的真正工作差异。
挂起函数如何在内部工作?延续块如何帮助在暂停后恢复计算。 协程内代码行的顺序计算如何不阻塞线程?它比线程并发更好吗?
【问题讨论】:
标签: android kotlin concurrency kotlin-coroutines
挂起函数在内部是如何工作的?
简而言之,在 Java 平台上,suspend fun 编译为与普通函数截然不同的字节码。它接收一个隐藏的额外参数(延续),创建自己的延续对象,整个函数体(大约)实现为一个大的switch 语句,允许函数在恢复时跳转到函数体的中间.
当suspend fun 挂起时,底层Java 方法实际上会返回。返回值是一个特殊的COROUTINE_SUSPENDED 单例对象,框架知道如何解释它。 suspend fun 本身有责任将延续对象保存在函数的结果准备好时可以访问的位置。
official documentation 对这些细节有很好的深入描述。
延续块如何帮助暂停后恢复计算。
这与我上面所说的有关,suspend fun 本身负责确保它稍后恢复。它必须在函数suspendCoroutineOrReturn 提供的块内执行此操作。用户代码不会直接调用它,而是更高级的类似物suspendCoroutine 和suspendCancellableCoroutine。这些接管了在适当的线程上恢复协程的问题,开发人员只负责确保在结果可用时调用continuation.resume()。这通常发生在您传递给异步调用的回调中。
您可以学习this answer,它试图在一个独立的示例中解释暂停-恢复机制。
协程内部代码行的顺序计算如何不阻塞线程?
因为它实际上是从函数编译成返回,然后通过跳转到函数体的中间来恢复。
它比线程并发好在哪里?
本机线程是重量级资源,需要时间来创建和销毁。协程的重量要轻得多,因此您可以更快地启动更多协程。
【讨论】:
内部工作原理在原始设计文档https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md 中进行了说明,其中有一个关于“实施细节”的部分。
【讨论】: