【问题标题】:Why the coroutine scope launches are run by different thread?为什么协程范围启动由不同的线程运行?
【发布时间】:2021-09-05 07:32:12
【问题描述】:
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

private val started = System.currentTimeMillis()

suspend fun main(args: Array<String>) {
    debug("Start run blocking")
    debug("starting")
    coroutineScope {
        debug("Inside runBlocking")
        val time = measureTimeMillis {
            val one = launch { doSomethingUsefulOne() }
            val two = launch { doSomethingUsefulTwo() }
            debug("awaiting")
//            two.await()
//            one.await()
            debug("Finished")
        }
        debug("time = $time")
    }
    debug("ending")
    debug("End run blocking")
}

suspend fun doSomethingUsefulOne(): Int {
    debug("Inside doSomethingUsefulOne")
    delay(3000L)
    debug("first")
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    debug("Inside doSomethingUsefulTwo")
    delay(1000L)
    debug("second")
    return 29
}
private fun debug(s: String) {
    val elapsed = System.currentTimeMillis() - started
    println("[time elapsed : $elapsed] $s  --  ${Thread.currentThread()}")
}

我正在使用上面的代码来学习协程的行为。我得到预期的行为如下:

[time elapsed : 15] Start run blocking  --  Thread[main,5,main]
[time elapsed : 16] starting  --  Thread[main,5,main]
[time elapsed : 34] Inside runBlocking  --  Thread[main,5,main]
[time elapsed : 77] Inside doSomethingUsefulOne  --  Thread[DefaultDispatcher-worker-1,5,main]
[time elapsed : 80] awaiting  --  Thread[main,5,main]
[time elapsed : 80] Finished  --  Thread[main,5,main]
[time elapsed : 80] Inside doSomethingUsefulTwo  --  Thread[DefaultDispatcher-worker-2,5,main]
[time elapsed : 80] time = 46  --  Thread[main,5,main]
[time elapsed : 1089] second  --  Thread[DefaultDispatcher-worker-2,5,main]
[time elapsed : 3088] first  --  Thread[DefaultDispatcher-worker-2,5,main]
[time elapsed : 3089] ending  --  Thread[DefaultDispatcher-worker-2,5,main]
[time elapsed : 3089] End run blocking  --  Thread[DefaultDispatcher-worker-2,5,main]

在这里,我无法了解启动是如何在不同线程上运行的,因为它应该利用主线程(如果我在这里)。此外,在 coroutineScope 之外,它的工作线程打印最后两条语句,因为这应该由主线程运行。

我想知道我哪里出错了?

【问题讨论】:

  • 我认为您的日志消息与您的代码不匹配,但无论如何忽略该启动是协程构建器。 kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/… 它与其余代码同时启动一个新的协程,该协程继续独立工作,这意味着它将在主线程之外运行。对于第二个问题,需要查看实际代码和日志,因为它们不匹配不知道要得出什么结论。
  • @ManojMohanty 没收到。这里的日志有什么问题?
  • 您发布的代码几乎不包含您发布的日志中的任何消息——反之亦然。
  • @MarkoTopolnik 已更正日志。你现在可以检查吗?主要的疑问是为什么日志中的最后两行由默认调度程序运行。如果我理解正确,那么它应该由主线程运行。
  • 为什么您的日志消息与代码实际执行的操作相矛盾?看起来很可疑,好像您没有重复运行,只是编辑了您发布的代码。

标签: kotlin asynchronous kotlin-coroutines


【解决方案1】:

您永远不会指定任何协程调度程序来在这里启动您的协程。这 suspend fun main 给你一个空的上下文(没有调度器),coroutineScope 也不添加任何调度器。

然后您使用 launch 不带参数来启动您的 2 个协程。正如文档所说:

如果上下文没有任何调度程序或任何其他 ContinuationInterceptor,则使用 Dispatchers.Default。

这意味着您的协程将使用Dispatchers.Default 分派,它根据您拥有的 CPU 内核数量提供多个工作线程。

如果您想在主线程上运行这些协程,您可以改用launch(Dispatchers.Main)(但它仅在 Android 和 JavaFX AFAIK 等特殊环境中可用)。

【讨论】:

  • 同意,但为什么最后两条语句由默认线程而不是主线程运行。他们甚至超出了范围?
  • @Garrick 由于没有为其余代码指定调度程序,我想没有理由进行上下文切换,因此它保留在 Dispatchers.Default 的工作线程中。您可以使用withContext 显式切换到某些特定线程。但是,如果您不在 Android 或 JavaFX 中,我认为您不能使用 Dispatchers.Main
猜你喜欢
  • 2014-06-17
  • 1970-01-01
  • 2021-02-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多