Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make sense of Kotlin coroutines?

I have tried reading various tutorials and pages on Kotlin coroutines and even though it kind of makes sense to me, I still don't feel it has clicked and I dont feel ready to jump on writing async non-blocking code with coroutines. I think what i am missing is a diagram or picture of what exactly happens and in what order when a piece of coroutine code executes. How does that code run at the thread level?

    launch {
        delay(1000)
        println("World (${currentThread().name})")
    }
    println("Hello (${currentThread().name})")
    sleep(1500)

My understanding is this. I am happy to be corrected or given a different example to further my understanding.

Line0: Code starts on main thread

Line1: Launches a new coroutine on a new thread (from forkjoin pool i suppose)

Line2: Suspending function so the coroutine suspends and returns the thread to the thread pool (hence being non-blocking)

Line5: Prints on the main thread

Line6: Blocks the main thread for 1.5s

Line3: The coroutine resumes execution on (not sure which thread here - same as the thread before suspension or can be a different thread?). The coroutines prints on that thread and finishes, hence returning the thread to the pool again.

Another question i have is how would the low-level execution change if i wrap the whole code around runBlocking { ... }

like image 721
chaosmonk Avatar asked Jul 28 '19 18:07

chaosmonk


People also ask

What are Kotlin coroutines good for?

Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages. On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive.

How Kotlin coroutines are better than RxJava?

Kotlin coroutines provide much more flexibility than plain reactive programming (the code can be written in an easy to understand sequential way whenever reactive programming is not needed, but can still be written in a reactive programming style when needed by making use of the Kotlin operators on collections)

When should you not use coroutines?

Answer: a. You should not use them for any foreground task.

Why coroutines are better than RxJava?

The reason is coroutines makes it easier to write async code and operators just feels more natural to use. As a bonus, Flow operators are all kotlin Extension Functions, which means either you, or libraries, can easily add operators and they will not feel weird to use (in RxJava observable.


1 Answers

Your code doesn't actually do anything that would reveal the special nature of coroutines. It makes two threads do their thing concurrently, just as they would do it in plain Java.

It only gets interesting when you launch a coroutine on the same thread you're already on (for example, the main thread). This is one of the things you achieve with a runBlocking block:

runBlocking {
    launch {
        delay(1000)
        println("Hello from the launched coroutine. My thread is "
                + Thread.currentThread().name)
    }
    println("Hello from the top-level coroutine. My thread is "
            + Thread.currentThread().name)
}

This will print

Hello from the top-level coroutine. My thread is main
Hello from the launched coroutine. My thread is main

runBlocking runs an event loop on the calling thread and propagates a reference to it to all the coroutines you launch within it. For example, delay(1000) will post an event to this event loop, with an indicated delay of one second, and then it will suspend the coroutine. This will allow the main thread to run the rest of the code below launch. When the time elapses, the event loop will run the event handler, which will in turn resume the coroutine.


An even more educational example is launching a coroutine without any Dispatcher. This removes the illusion of coroutines looking like threads and reveals their true magic: by calling continuation.resume() you make the current thread jump right into the middle of the suspended coroutine's block of code, and all that happens using plain Java method calls. I suggest studying this answer where this is explained in detail. If you're interested in an even more in-depth explanation of how plain Java methods can do this trick, I suggest you watch Roman Elizarov explaining this on YouTube.

like image 165
Marko Topolnik Avatar answered Sep 28 '22 08:09

Marko Topolnik