Kotlin 中线程和协程的区别 [英] Difference between thread and coroutine in Kotlin

查看:26
本文介绍了Kotlin 中线程和协程的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Kotlin 中是否有任何特定语言实现,它与协程的其他语言实现不同?

  • 协程就像轻量级线程是什么意思?
  • 有什么区别?
  • kotlin 协程实际上是并行/并发运行的吗?
  • 即使在多核系统中,在任何给定时间也只有一个协程在运行(对吗?)

这里我启动了 100000 个协程,这段代码背后发生了什么?

for(i in 0..100000){异步(公共池){//运行长时间运行的操作}}

解决方案

由于我只在 JVM 上使用了协程,所以我将谈论 JVM 后端,还有 Kotlin Native 和 Kotlin JavaScript,但这些 Kotlin 后端超出了我的范围.

那么让我们从比较 Kotlin 协程与其他语言的协程开始.基本上,你应该知道有两种类型的 Coroutines:stackless 和 stackful.Kotlin 实现了无堆栈协程——这意味着协程没有自己的堆栈,这限制了协程可以做什么.你可以阅读一个很好的解释 此处.

示例:

  • 无堆栈:C#、Scala、Kotlin
  • Stackful:类星体、Javaflow
<块引用>

协程就像轻量级线程是什么意思?

这意味着 Kotlin 中的协程没有自己的堆栈,它不会映射到本地线程,也不需要处理器上的上下文切换.

<块引用>

有什么区别?

线程 - 抢占式多任务处理.(通常).协程 - 协作式多任务处理.

线程 - 由操作系统管理(通常).协程 - 由用户管理.

<块引用>

kotlin 的协程实际上是并行/并发运行的吗?

这取决于,您可以在自己的线程中运行每个协程,也可以在一个线程或某个固定线程池中运行所有协程.

更多关于协程如何执行 此处.

<块引用>

即使在多核系统中,在任何给定时间也只有一个协程在运行(对吗?)

不,请参阅上一个答案.

<块引用>

这里我启动了 100000 个协程,这段代码背后发生了什么?

实际上,这取决于.但是假设您编写了以下代码:

fun main(args: Array) {对于(我在 0..100000 中){异步(公共池){延迟(1000)}}}

此代码立即执行.

因为我们需要等待 async 调用的结果.

所以让我们解决这个问题:

fun main(args: Array) = runBlocking {对于(我在 0..100000 中){val 作业 = 异步(CommonPool){延迟(1)打印(一)}工作.加入()}}

当您运行这个程序时,kotlin 将创建 2 * 100000 个 Continuation 实例,这将占用几十 Mb 的 RAM,并且在控制台中,您将看到从 1 到 100000 的数字.

那么让我们以这种方式重写这段代码:

fun main(args: Array) = runBlocking {val 作业 = 异步(CommonPool){对于(我在 0..100000 中){延迟(1)打印(一)}}工作.加入()}

我们现在实现了什么?现在我们只创建了 Continuation 的 100001 个实例,这要好得多.

每个创建的 Continuation 都会在 CommonPool(它是 ForkJoinPool 的静态实例)上分派和执行.

Is there any specific language implementation in Kotlin, which differs it from another languages implementation of coroutines?

  • What means that coroutine is like light-weight thread?
  • What is the difference?
  • Are kotlin coroutines actually running in parallely / concurrently?
  • Even in multi-core system, there is only one coroutine running at any given time (is it right?)

Here I'm starting 100000 coroutines, what happens behind this code?

for(i in 0..100000){
   async(CommonPool){
    //run long running operations
  }
}

解决方案

Since I used coroutines only on JVM, I will talk about JVM backend, there are also Kotlin Native and Kotlin JavaScript but these backends for Kotlin are out of my scope.

So let's start with comparing Kotlin coroutines to other languages coroutines. Basically, you should know that there are two types of Coroutines: stackless and stackful. Kotlin implements stackless coroutines - it means that coroutine doesn't have its own stack, and that limiting a little bit what coroutine can do. You can read a good explanation here.

Examples:

  • Stackless: C#, Scala, Kotlin
  • Stackful: Quasar, Javaflow

What it means that coroutine is like light-weight thread?

It means that coroutine in Kotlin doesn't have its own stack, it doesn't map on a native thread, it doesn't require context switching on a processor.

What is the difference?

Thread - preemptively multitasking. (usually). Coroutine - cooperatively multitasking.

Thread - managed by OS (usually). Coroutine - managed by a user.

Are kotlin's coroutines actually running in parallel / concurrently?

It depends, you can run each coroutine in its own thread, or you can run all coroutines in one thread or some fixed thread pool.

More about how coroutines execute here.

Even in a multi-core system, there is only one coroutine running at any given time (is it right?)

No, see the previous answer.

Here I'm starting 100000 coroutines, what happens behind this code?

Actually, it depends. But assume that you write the following code:

fun main(args: Array<String>) {
    for (i in 0..100000) {
        async(CommonPool) {
            delay(1000)
        }
    }
}

This code executes instantly.

Because we need to wait for results from async call.

So let's fix this:

fun main(args: Array<String>) = runBlocking {
    for (i in 0..100000) {
        val job = async(CommonPool) {
            delay(1)
            println(i)
        }

        job.join()
    }
}

When you run this program kotlin will create 2 * 100000 instances of Continuation, which will take a few dozen Mb of RAM, and in console, you will see numbers from 1 to 100000.

So lets rewrite this code in this way:

fun main(args: Array<String>) = runBlocking {

    val job = async(CommonPool) {
        for (i in 0..100000) {
            delay(1)
            println(i)
        }
    }

    job.join()
}

What we achieve now? Now we create only 100001 instances of Continuation, and this is much better.

Each created Continuation will be dispatched and executed on CommonPool (which is a static instance of ForkJoinPool).

这篇关于Kotlin 中线程和协程的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆