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 之外,它的工作线程打印最后 2 条语句,因为这应该由主线程运行。
我想知道我哪里出错了?
最佳答案
您永远不会在此处指定任何协程调度程序来启动您的协程。这
suspend fun main
为您提供一个空上下文(没有调度程序),并且 coroutineScope
也不会添加任何调度程序。
然后您可以使用 launch无需参数即可启动您的 2 个协程。正如医生所说:
If the context does not have any dispatcher nor any other ContinuationInterceptor, then Dispatchers.Default is used.
这意味着您的协程将使用 Dispatchers.Default 进行调度它根据您拥有的 CPU 核心数量提供多个工作线程。
如果您想在主线程上运行这些协程,则可以使用 launch(Dispatchers.Main)
(但它仅在 Android 和 JavaFX AFAIK 等特殊环境中可用)。
关于kotlin - 为什么协程作用域启动由不同的线程运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69061403/