问题描述
在kotlin中考虑以下代码.
Consider the following code in kotlin.
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
println("inside coroutine")
}
println("outside coroutine")
我们在Main(UI)线程中创建一个协程,协程后有一些代码.
我知道在真实代码中执行此操作没有多大意义,但这只是一个理论问题.
We create a coroutine in the Main(UI) thread and there is some code after the coroutine.
I know it doesn´t make much sense to do that in real code, but it´s just a theoretical question.
考虑到协程在主线程中运行,为什么总是先执行 println("outside coroutine") ?
我本以为有时我会先看到 协程外 ,而有时会看到第一个 协程内 ,就像两个线程.
谁(操作系统或协程实现)决定先运行协程之外的coe?
Considering that the coroutine runs in the Main thread, why println("outside coroutine") is ALWAYS executed first?
I would have expected that sometimes i would see first outside coroutine and other times, first inside coroutine, kind of like two threads.
Who (OS or Coroutines implementation) decides that the coe outside the coroutine is run first?
推荐答案
让我们想象您的代码是这样的:
Let's imagine that your code instead was this:
someView.post {
println("inside post")
}
println("outside post")
在这里,我们创建一个Runnable
(lambda表达式),并将其传递给某些View
上的post()
. post()
表示Runnable
最终将在主应用程序线程上为run()
.将Runnable
放在驱动主应用程序线程的Looper
使用的工作队列上,并在Runnable
到达队列顶部时执行(或多或少—详细信息是较杂乱的IIRC,但是在这里不重要).
Here, we create a Runnable
(lambda expression) and pass that to post()
on some View
. post()
says that the Runnable
will be run()
on the main application thread... eventually. That Runnable
is put on the work queue that the Looper
powering the main application thread uses, and it gets executed when that Runnable
gets to the top of the queue (more or less — the details are messier IIRC but not important here).
但是,如果您在主应用程序线程上执行此代码,则将始终先打印println("outside post")
. Runnable
放在队列中以待稍后执行,但是您仍在主应用程序线程上执行,因此即使队列为空,在您返回主应用程序线程的控制权之前,该Runnable
也不会运行回到Android.因此,在调用post()
之后,将继续执行println("outside post")
.
But if you are executing this code on the main application thread, println("outside post")
will always be printed first. The Runnable
is placed onto the queue to be executed later, but you are still executing on the main application thread, and so even if the queue were empty, that Runnable
will not run until you return control of the main application thread back to Android. So, after the call to post()
, execution continues with println("outside post")
.
在幕后,Dispatchers.Main
基本上是使用post()
(同样,细节更为复杂,但对于本次讨论而言不太重要).因此,当您协程时,该lambda表达式将排队等待最终在主应用程序上执行.但是,您已经在主应用程序线程上,因此执行可以正常继续,并且println("outside post")
在协程有机会执行任何操作之前被打印出来.
Under the covers, Dispatchers.Main
is basically using post()
(again, the details are more complicated but not too important for this discussion). So, when you launch()
the coroutine, that lambda expression gets queued up to be executed eventually on the main application. But, you are already on the main application thread, so execution continues normally, and the println("outside post")
gets printed before the coroutine gets a chance to do anything.
假设您的代码是:
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
println("inside coroutine")
}
scope.launch {
println("inside another coroutine")
}
现在您处于一种理论上可以首先打印其中任何一行的情况.您要同时排队两个lambda表达式,由调度程序决定在什么时候在什么线程上运行什么.实际上,如果始终先打印内部协程",这不会令我感到惊讶,因为Dispatchers.Main
的简单实现将在没有其他约束的情况下使用FIFO排序(例如,协程在I/O上被阻塞).但是,您不应该假定这两个协程的特定调用顺序.
Now you are in a situation where in theory either of those lines could be printed first. You are queuing up both lambda expressions, and it is up to the dispatcher to decide what to run on what thread at what point. In practice, it would not surprise me if "inside coroutine" is always printed first, as a simple implementation of Dispatchers.Main
would use FIFO ordering in the absence of other constraints (e.g., a coroutine is blocked on I/O). However, you should not assume a particular order of invocation of those two coroutines.
这篇关于协程的执行顺序是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!