美文网首页Kotlin-Coroutines
Kotlin-轻量级协程与线程执行比对分析

Kotlin-轻量级协程与线程执行比对分析

作者: 蒋斌文 | 来源:发表于2021-06-13 10:19 被阅读0次

    轻量级协程与线程执行比对分析

    作用域构建器

    除了由不同的构建器提供协程作用域之外,还可以使用 coroutineScope 构建器声明自己的作用域。它会创建一 个协程作用域并且在所有已启动子协程执行完毕之前不会结束
    runBlocking 与 coroutineScope 可能看起来很类似,因为它们都会等待其协程体以及所有子协程结束。主要 区别在于,runBlocking 方法会阻塞当前线程来等待,而 coroutineScope 只是挂起,会释放底层线程用于其他 用途。由于存在这点差异,runBlocking 是常规函数,而 coroutineScope 是挂起函数。

    fun main() = runBlocking {
        launch {
            delay(1000)
            println("my job1")
        }
    
        println("person")
    
        coroutineScope {
            launch {
                delay(3000)
                println("my job2")
            }
    
            delay(2000)
            println("hello world")
        }//如果其中的协程挂起,那么coroutineScope函数也会挂起
        println("welcome")
    }
    

    RUN> 🏄🏄🏄🏄🏄🏄

    person
    my job1
    hello world
    my job2
    welcome
    
    Process finished with exit code 0
    
    image-20210611164701768 image-20210611164857193

    Creates a CoroutineScope and calls the specified suspend block with this scope. The provided scope inherits its coroutineContext from the outer scope, but overrides the context's Job.

    创建一个coroutinscope并使用此范围调用指定的挂起块。提供的作用域从外部作用域继承其coroutineContext,但覆盖了上下文的Job。

    轻量级协程与线程执行比对分析:

    对于协程的效果跟线程其实差不多,但是它们俩其实还是存在本质的区别的,总的来说协程是轻量级的,而线程是重量级的。所以下面来做下实验来看一下它们两者的区别:

    先来看下协程的效果,这里创建N个协程然后输出个字母,当然我们可以用for循环来创建多个,这里采用Kotlin的方式来实现一下:

    fun main() = runBlocking {
        repeat(5000) {
            launch {
                delay(1000)
                println("A")
            }
        }
    
        println("Hello World")
    }
    

    repeat函数

    @kotlin.internal.InlineOnly
    public inline fun repeat(times: Int, action: (Int) -> Unit) {
        contract { callsInPlace(action) }
    
        for (index in 0 until times) {//函数内部执行times循环
            action(index)
        }
    }
    

    Executes the given function action specified number of times.

    执行给定action的函数times次。一个当前迭代基于0的索引会当成参数传给action

    image-20210611165441396

    比较容易,接下来咱们换成线程来实现同样的效果

    fun main() {
        repeat(5000) {
            thread {
                Thread.sleep(1000)
                println("A")
            }
        }
        println("Hello World")
    }
    

    RUN> 🏄🏄🏄🏄🏄🏄

    [0.780s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 4k, detached.
    Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
      at java.base/java.lang.Thread.start0(Native Method)
      at java.base/java.lang.Thread.start(Thread.java:801)
      at kotlin.concurrent.ThreadsKt.thread(Thread.kt:42)
      at kotlin.concurrent.ThreadsKt.thread$default(Thread.kt:25)
      at com.shengsiyuan.coroutines.HelloKotlin9Kt.main(HelloKotlin9.kt:7)
      at com.shengsiyuan.coroutines.HelloKotlin9Kt.main(HelloKotlin9.kt)
    [0.944s][warning][os,thread] Failed to start thread - pthread_create failed (EAGAIN) for attributes: stacksize: 1024k, guardsize: 4k, detached.
    Error occurred during initialization of VM
    java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
    
    Process finished with exit code 1
    

    区别就出来啦!!!由于协程是用户态,没有个数的上限,而线程是内核态的,它需要依赖于系统,是有上限的,另外由于线程有切换的开销,所以在有些情况会能看到线程的执行速度要比协程要慢,当然在我电脑上木有看出来,验证出来的结论就是协程是轻量级的,而线程是重要级的

    repeat()函数的一个细节,这个细节可能比较难理解,但是理解了之后能够让我们更加正确的用Kotlin的思维去编写代码,先来看一下它的参数定义:

    image-20210611165947861 image-20210611170223625

    我们看到的repeat()的第二个参数的Lambda表达式是要求要能接收一个参数呢,那怎么我们就能传lauch()函数给repeat()的第二个参数呢?

    image-20210611170815166

    这也是Kotlin跟Java不一样的地方,也就是如果只有一个参数时在写Lambda表达式是可以省略的,接下来我们来把这个隐含的参数打出来:

    image-20210611171237191

    这个细节非常之小,可能不一定每个人都能去研究它,但是研究透了之后其实也就是让我们更好的能使用Kotlin的一个基石。

    相关文章

      网友评论

        本文标题:Kotlin-轻量级协程与线程执行比对分析

        本文链接:https://www.haomeiwen.com/subject/hheveltx.html