- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
Kotlin 如何在内部实现协程?
协程被称为线程的“轻量级版本”,据我了解,它们在内部使用线程来执行协程。
当我使用任何构建器函数启动协程时会发生什么?
这是我对运行这段代码的理解:
GlobalScope.launch { <---- (A)
val y = loadData() <---- (B) // suspend fun loadData()
println(y) <---- (C)
delay(1000) <---- (D)
println("completed") <---- (E)
}
ThreadPool
。(A)
处,Kotlin 开始在下一个可用的空闲线程(比如 Thread01
)中执行协程。(B)
处,Kotlin 停止执行当前线程,并在下一个可用的空闲线程(Thread02
)。(B)
执行后返回时,Kotlin 在下一个可用的空闲线程(Thread03
)中继续协程。(C)
在 Thread03
上执行。(D)
处,Thread03
停止。(E)
在下一个空闲线程上执行,比如 Thread01
。我理解正确吗?还是协程以不同的方式实现?
2021 年更新: Here's an excellent article由 Manuel Vivo 提供,补充了以下所有答案。
最佳答案
协程与您描述的任何调度策略完全不同。协程基本上是 suspend fun
的调用链。暂停完全由您控制:您只需调用 suspendCoroutine
。您将获得一个回调对象,因此您可以调用它的 resume
方法并返回到您暂停的位置。
这里有一些代码,你可以看到暂停是一个非常直接和透明的机制,完全在你的控制之下:
import kotlin.coroutines.*
import kotlinx.coroutines.*
var continuation: Continuation<String>? = null
fun main(args: Array<String>) {
val job = GlobalScope.launch(Dispatchers.Unconfined) {
while (true) {
println(suspendHere())
}
}
continuation!!.resume("Resumed first time")
continuation!!.resume("Resumed second time")
}
suspend fun suspendHere() = suspendCancellableCoroutine<String> {
continuation = it
}
上面的所有代码都在同一个主线程上执行。根本没有多线程。
您launch
的协程每次调用suspendHere()
时都会自行挂起。它将延续回调写入 continuation
属性,然后您显式使用该延续来恢复协程。
代码使用 Unconfined
协程调度器,它根本不分派(dispatch)到线程,它只是在您调用 continuation.resume()
的地方运行协程代码。
考虑到这一点,让我们重新审视您的图表:
GlobalScope.launch { <---- (A)
val y = loadData() <---- (B) // suspend fun loadData()
println(y) <---- (C)
delay(1000) <---- (D)
println("completed") <---- (E)
}
- Kotlin has a pre-defined
ThreadPool
at the beginning.
它可能有也可能没有线程池。 UI 调度程序与单个线程一起工作。
线程成为协程调度器目标的先决条件是有一个与之关联的并发队列,并且该线程运行一个顶级循环,该循环从该队列中获取 Runnable
对象,并且执行它们。协程调度器只是将延续放在该队列中。
- At
(A)
, Kotlin starts executing the coroutine in the next available free thread (SayThread01
).
它也可以是你调用 launch
的同一个线程。
- At
(B)
, Kotlin stops executing the current thread, and starts the suspending functionloadData()
in the next available free thread (Thread02
).
Kotlin 不需要为了挂起协程而停止任何线程。事实上,协程的主要观点是线程不会启动或停止。线程的顶级循环将继续并选择另一个 runnable 来运行。
此外,您调用 suspend fun
的事实没有任何意义。协程只有在显式调用 suspendCoroutine
时才会挂起。该函数也可以简单地返回而不暂停。
但我们假设它确实调用了 suspendCoroutine
。在这种情况下,协程不再在任何线程上运行。它被暂停并且无法继续,直到某个代码在某处调用continuation.resume()
。该代码可以在未来任何时间在任何线程上运行。
- When
(B)
returns after execution, Kotlin continues the coroutine in the next available free thread (Thread03
).
B
不会“执行后返回”,协程仍在其主体内时恢复。它可以在返回之前暂停和恢复任意次数。
(C)
executes onThread03
.- At
(D)
, theThread03
is stopped.- After 1000ms,
(E)
is executed on the next free thread, sayThread01
.
再一次,没有线程被停止。协程被挂起,并且通常特定于调度程序的机制用于安排其在 1000 毫秒后恢复。此时它将被添加到与调度程序关联的运行队列中。
为了具体起见,让我们看一些示例,说明调度协程需要什么样的代码。
Swing UI 调度程序:
EventQueue.invokeLater { continuation.resume(value) }
Android UI 调度程序:
mainHandler.post { continuation.resume(value) }
ExecutorService 调度器:
executor.submit { continuation.resume(value) }
关于kotlin - Kotlin 协程如何在内部工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53526556/
我正在查看Kotlin Github page我注意到 Kotlin 语言本身大部分是用 Kotlin 编写的:我只是想知道,一种语言怎么可能大部分都是用它自己的语言编写的?在您可以使用正在创建的语言
我有以下非常简单的 kotlin 代码来演示中缀函数 com.lopushen.demo.presentation 包 fun main(args: Array) { print("Hello
我在 Java 中有 2 个模型类,其中一个扩展了另一个 @UseStag public class GenericMessages extends NavigationLocalizationMap
Kotlin 代码 runBlocking { flow { for (i in 0..4) { println("Emit $i")
这三个 Kotlin 插件和它们的实际作用有什么区别? plugins { id 'kotlin-android' id 'org.jetbrains.kotlin.android'
我正在为某些现有库添加 Kotlin 原生 linuxX64 目标支持。库已成功编译,但在运行测试用例时,出现以下运行时错误: kotlin.native.concurrent.InvalidMuta
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 2 年前。 Improve t
我创建了一个类并向其添加了一个与成员函数具有相同签名的扩展,并执行了这个方法,它总是执行成员方法。 class Worker { fun work() = "...working" } fun
我知道传递给函数的参数将被视为“val”,即使变量被初始化为“var”。但这对我来说一直是个问题。在下面的示例代码中,我想通过使用函数“changeNum”修改变量“num”的值。但当然,Kotlin
现在,我正在尝试用 Kotlin 重写我的 Java 应用程序。然后,我遇到了日志语句,比如 log.info("do the print thing for {}", arg); 所以我有两种方法可
有点出名article关于许多语言的异步编程模型的状态,指出它们存在“颜色”问题,特别是将生态系统分为两个独立的世界:异步和非异步。以下是这种语言的属性: 每个函数都有一种颜色,红色或蓝色(例如asy
因为 KDoc 文档生成引擎是 abandoned in favor of Dokka , Kotlin 文档应该称为“KDoc 注释”,还是“Dokka 注释”? 最佳答案 如所述here , KD
我想在可空对象上传递函数引用。以 Android 为例,假设我想使用 Activity#onBackPressed来自作为该事件的子级的片段。 如果我想调用这个函数,我可以很容易地做到 activit
我有一个列表 (x, y)其中y只能是 0 或 1 这样 例如: [(3, 0), (3, 1), (5, 1)] [(5, 0), (3, 1), (5, 1)] [(1, 1), (3, 1),
从强类型语言的定义来看: A strongly-typed programming language is one in which each type of data (such as intege
这不能编译的事实是否意味着它们不是一流的类型? fun foo(s: String): Int = s.length // This won't compile. val bar = foo 有没有办
如果在 Java i++是一个表达式和 i++;是一个表达式语句,分号(;) 在 Kotlin 中是可选的,是 i++ Kotlin 中的表达式或表达式语句? 最佳答案 i++是一个表达式,因为它有一
代码(如下所示)是否正确?它取自 Kotlin-docs.pdf 的第 63 页,这也是 https://kotlinlang.org/docs/reference/generics.html 的最后
我正在尝试使用 Kotlin 为 Android 的一些全局 API 解析器(检查网络连接、调用 API 并通过来自源的单个调用返回格式化数据),并且在某些时候我不得不创建一个通用类型 object就
kotlinlang 中的任务: 使用月份变量重写此模式,使其与格式 13 JUN 1992(两位数字、一个空格、一个月份缩写、一个空格、四位数字)中的日期相匹配。 答案是:val month = "
我是一名优秀的程序员,十分优秀!