Reputation: 417
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 { ... }
Upvotes: 9
Views: 3510
Reputation: 200148
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.
Upvotes: 6
Reputation: 1845
Here is another example metioned here: https://kotlinlang.org/docs/reference/coroutines/basics.html#your-first-coroutine
fun main() {
GlobalScope.launch { // launch a new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
The above code prints:
Hello,
World!
As you can see, although the code looks synchronous, the execution is asynchronous. That's the whole idea of Coroutine.
Upvotes: 1