简体   繁体   中英

How Kotlin coroutines are scheduled

I've been reading a lot of articles and watching a lot of videos on Kotlin co-routines lately and, despite my efforts, I still can't make sense of them in my head.

I think I've finally found a way to illustrate my problem:

class MyViewModel() : CoroutineScope {

override val coroutineContext = Dispatchers.Main + Job()

    fun foo() = launch(handler) {
        Log.e("test", "A")
    }
}

class MainActivity : Activity() {
    override fun onCreate() {
        MainViewModel().foo()
        Log.e("test", "B")
    }
}

The output of this is:

E/test: B
E/test: A

And I don't get how this can be the case, I'm using only one thread (the main thread). If my code executes sequentially, by the time I reach the line log(B) ... log(A) should have already be printed.

Does the coroutines library use other threads internally to accomplish this? This is the only explanation I could come up with but haven't found anything saying so in the docs.

PS: Sorry for throwing android into the mix but this code:

fun main() {
    GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
        print(Thread.currentThread().name + "World!") // print after delay
    }
    (0 .. 1000).forEach { print(".") }
}

seems to work as expected and prints: main @coroutine#1World!...........................

because 1 thread == sequential work

Hope my question makes sense, thanks for reading!

Under the hood, the Main dispatcher uses a Handler to post a Runnable to the MessageQueue. Basically, it'll get added to the end of the event queue. This means it will execute soon, but not immediately. Hence why “B” gets printed before “A”.

You can find more information in this article .

EDIT by OP (read the article above before reading this):

Just wanted to clarify why the android example above was working fine, in case someone is still wondering.

fun main() {
    GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
        print(Thread.currentThread().name + "World!") // print after delay
    }
    (0 .. 1000).forEach { print(".") }
}

We're setting GlobalScope to use the UNCONFINED dispatcher, and this dispatcher has isDispatchNeeded set to false . false means "schedule in the current thread", and that's why we see the logs printing sequentially. UNCONFINED should not be used in regular code.

All other dispatchers have isDispatchNeeded set to true even the UI dispatcher. see: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/is-dispatch-needed.html

(btw GlobalScope uses the Default dispatcher if we don't specify one)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM