https://kotlinlang.org logo
#coroutines
Title
# coroutines
d

David Kubecka

10/16/2023, 1:52 PM
What is the intended/recommended way of setting context for
runBlocking
? Directly via runBlocking parameter
Copy code
runBlocking(<http://Dispatchers.IO|Dispatchers.IO>) {
...
}
or via
withContext
?
Copy code
runBlocking {
  withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
...
  }
}
Quick debugging confirms my interpretation of the documentation that in the second case the internal
eventLoop
is not defined although I have no clue exactly what consequences this has. Can anyone shed more light on this?
s

simon.vergauwen

10/16/2023, 2:11 PM
runBlocking
has a
context
parameter, so
runBlocking(<http://Dispatchers.IO|Dispatchers.IO>) { }
d

David Kubecka

10/16/2023, 2:16 PM
Yes, I know (see my first example). I'm asking whether there's any difference to my second example (where I verified that the internal
eventLoop
variable is null).
I'm basically asking if I need that default
eventLoop
dispatcher or I can safely replace it with my own dispatcher (which possibly doesn't implement
eventLoop
).
s

Sam

10/16/2023, 2:50 PM
I'd just provide the context directly, as in your first example. Otherwise you're creating the event loop and then not using it for anything. Although there are behaviour differences between using the event loop and not using it, there's no meaningful difference between the two different ways of not using it.
2
d

David Kubecka

10/17/2023, 7:05 AM
Oh, so the event loop is actually. useless in my case. So can it be said that providing (any?) explicit dispatcher fully replaces the need to use the event loop?
s

Sam

10/17/2023, 7:10 AM
Yes 👍. If there's no event loop, the current thread will just block and wait for the job to finish.
👍 2
d

David Kubecka

10/17/2023, 7:31 AM
But technically the event loop also blocks the underlying thread and the calling code waits for runBlocking to finish, right? So what's the difference?
s

simon.vergauwen

10/17/2023, 7:35 AM
The thread is being blocked by
LockSupport.park
and it's being undone by
LockSupport.unpark
so the eventloop is not responsible for that. The eventloop is meant such that you can return to the caller thread within the coroutine system for context preservation). Take following example:
Copy code
suspend fun main() {
   println(Thread.currentThread().name) // main
   withContext(Dispatchers.Default) {
     println(Thread.currentThread().name) // default-worker
   }
   println(Thread.currentThread().name) // default-worker
}

fun main(): Unit = runBlocking {
   println(Thread.currentThread().name) // main
   withContext(Dispatchers.Default) {
     println(Thread.currentThread().name) // default-worker
   }
   println(Thread.currentThread().name) // main
}
Thanks to the eventloop the last thread printed in the
runBlocking
example is
main
👍 1
s

Sam

10/17/2023, 7:49 AM
The important bits of source code are (surprisingly) mostly in one file, so you can readily see what's going on. Here's the loop. • If
eventLoop
is
null
, the thread is just parked indefinitely, until the job completion triggers it to unpark. • If
eventLoop
is non-null, the thread is parked only when it runs out of events. If the event loop has events scheduled for the future, the thread is parked until those events are ready. Otherwise, it's parked indefinitely. It can be unparked either by completion of the job or by a new event being dispatched to the event loop.
1
d

David Kubecka

10/17/2023, 7:55 AM
Thanks! The example helped. The takeaway is (I hope) that unless I care about which thread continues the execution after a coroutine block then the distinction is quite insignificant.