由于我只在 JVM 上使用协程,所以我将讨论 JVM 后端,还有 Kotlin Native 和 Kotlin JavaScript,但这些 Kotlin 后端超出了我的范围。
让我们开始比较 Kotlin 协程和其他语言的协程。基本上,你应该知道协程有两种类型:stackless 和 stackful。 Kotlin 实现了无堆栈协程——这意味着协程没有自己的堆栈,这限制了协程的功能。你可以阅读一个很好的解释here。
例子:
- 无堆栈:C#、Scala、Kotlin
- 堆栈式:Quasar、Javaflow
协程就像轻量级线程是什么意思?
这意味着 Kotlin 中的协程没有自己的堆栈,它不映射到本机线程,它不需要处理器上的上下文切换。
有什么区别?
线程 - 抢先式多任务处理。 (usually)。
协程 - 协同多任务。
线程 - 由操作系统管理(通常)。
协程 - 由用户管理。
kotlin 的协程实际上是并行/并发运行的吗?
这取决于,您可以在自己的线程中运行每个协程,也可以在一个线程或某个固定线程池中运行所有协程。
更多关于协程如何执行here。
即使在多核系统中,任何时候也只有一个协程在运行(对吗?)
没有,看前面的回答。
这里我启动了 100000 个协程,这段代码背后发生了什么?
实际上,这取决于。但是假设你写了如下代码:
fun main(args: Array<String>) {
for (i in 0..100000) {
async(CommonPool) {
delay(1000)
}
}
}
此代码立即执行。
因为我们需要等待async 调用的结果。
所以让我们解决这个问题:
fun main(args: Array<String>) = runBlocking {
for (i in 0..100000) {
val job = async(CommonPool) {
delay(1)
println(i)
}
job.join()
}
}
当你运行这个程序时,kotlin 将创建 2 * 100000 个 Continuation 实例,这将占用几十 Mb 的 RAM,在控制台中,你会看到从 1 到 100000 的数字。
所以让我们用这种方式重写这段代码:
fun main(args: Array<String>) = runBlocking {
val job = async(CommonPool) {
for (i in 0..100000) {
delay(1)
println(i)
}
}
job.join()
}
我们现在取得了什么成就?现在我们只创建了 100001 个 Continuation 的实例,这要好得多。
每个创建的 Continuation 都将在 CommonPool(这是 ForkJoinPool 的静态实例)上调度和执行。