使用 launch 启动协程或使用 coroutineScope 启动协程之间的区别

lag*_*ine 3 kotlin kotlin-coroutines

看来我可以使用多种机制启动协程。其中两个是coroutineScopelaunch但阅读 Kotlin 协程文档时,我不清楚它们之间的区别是什么,以及何时使用其中一个而不是另一个

fun main() {
    println("Main block  ${Thread.currentThread().name}")
    runBlocking {
        coroutineScope {
            println("Coroutine scope  ${Thread.currentThread().name}")
        }
        launch {
            println("Launch  ${Thread.currentThread().name}")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我运行了上面的代码,可以看到两者都启动了一个新的协程。有什么不同?

cac*_*acs 9

ACoroutineScope是一个组织性的东西 - 它允许您将协程分组在一起以强制结构化并发。基本上,它允许您控制作用域内所有内容(包括在其他协程中启动的协程)的生命周期,并处理诸如传播结果和错误以及取消作用域内所有内容之类的事情。更多信息请点击此处

所有协程构建器函数(包括launch)都在a内部CoroutineScope运行(或者作为接收器运行a 上,如果你想这样看的话):

fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext, 
    start: CoroutineStart = CoroutineStart.DEFAULT, 
    block: suspend CoroutineScope.() -> Unit
): Job
Run Code Online (Sandbox Code Playgroud)

因此,launch示例中的调用在 current 内部运行,该 current 已由CoroutineScoperunBlocking构建器提供:

expect fun <T> runBlocking(
    context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): T
Run Code Online (Sandbox Code Playgroud)

看看你传递的 lambda 实际上是一个 吗CoroutineScope.() -> T?它以 aCoroutineScope作为接收器运行 - 这就是您所调用launch的。你不能从任何地方调用它!

CoroutineScope因此,当您在示例中创建 a 时,您将在所提供的内部嵌套一个。不允许其后面的其余代码继续(即它阻止执行),直到其中的所有内容都完成为止。在其中创建您自己的协程可以让您定义您可以控制的协程子集 - 您可以控制它们,但如果仍有其他协程在作用域中运行,它将继续阻塞,直到它们也完成为止。CoroutineScoperunBlockingrunBlockingCoroutineScopeCoroutineScopecancelrunBlocking


就像路易斯在另一个答案中所说的那样,您实际上并没有在您创建的范围内创建任何协程。该代码只是在runBlocking开始运行您传递的代码块的协程中运行。看一下这个:

fun main() {
    println("Main")
    runBlocking {
        coroutineScope {
            delay(1000)
            println("I'm in a coroutine scope")
        }
        launch {
            delay(500)
            println("First new coroutine")
        }
        launch {
            delay(50)
            println("Second new coroutine")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
Main
I'm in a coroutine scope
Second new coroutine
First new coroutine
Run Code Online (Sandbox Code Playgroud)

单个协程中的代码按顺序执行 - 所以会发生什么

  • 你从 main 开始
  • 您进入runBlocking块的协程
  • 你创建了一个CoroutineScope只影响你launch(等)在上面的东西
  • 你延迟,然后打印一行
  • 您点击第一个launch并创建一个新的协程。一开始会延迟 500 毫秒,但现在它自己运行 - 不同的协程同时运行
  • 您将转到下一行和launch第二个协程。它也会自行运行,并立即延迟 50 毫秒。现在有 3 个协程在运行
  • 您已经执行完块中的代码 - 该协程已完成。但是,还有两个正在运行的协程也已启动CoroutineScope,因此runBlocking请等待它们完成。
  • 延迟最短的第二个协程首先打印,然后完成
  • 第一个协程最后完成,因为尽管它启动较早,但它们都是独立运行的
  • 现在内部的一切runBlocking CoroutineScope都已完成,它可以完成并允许继续执行main()

如果您launch在您创建的范围内编辑了一个协程,那么它的工作方式都是相同的 - 只是您可以对其中的内容进行细粒度的控制,并且您可以专门使用该嵌套范围内的协程,而无需影响外部范围内的事物。重要的是一旦内部作用域完成,它可以通知外部作用域一切都完成了,诸如此类的事情


Lou*_*man 7

coroutineScope不启动新的协程。

launch启动一个可以与其他协程同时运行的新协程。 coroutineScope才不是。