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

charlesmuchene

03/13/2020, 1:31 PM
https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/04_Suspend “Coroutines are computations that run on top of threads and can be suspended. By saying “suspended”, we mean that the corresponding computation can be paused, removed from the thread, and stored in memory. When the computation is ready to be continued, it gets returned to a thread (but not necessarily to the same one).” Who works on the computation while it’s suspended? Another thread? Kotlin std library thread? I shouldn’t care?? 🤔 What am I missing on how coroutines work?
s

streetsofboston

03/13/2020, 1:41 PM
The calling thread is suspended at the point where a
suspend fun
is called. A(nother) thread in the thread-pool that is defined in the Coroutine’s Dispatcher, is then executing the
suspend fun
itself. When that thread is done executing the
suspend fun
, the calling thread resumes. In the mean time, the calling thread may have been doing some other stuff.
🎉 2
c

charlesmuchene

03/13/2020, 1:45 PM
Hmm. Okay. So a
suspend
is a like a cue to
Hey you Dispatcher threads. Work on this and let me know when you’re done?
👌 2
s

streetsofboston

03/13/2020, 1:45 PM
Note that if you call a
suspend fun
from a Coroutine whose Dispatcher has only one thread (e.g the main ui thread), and somewhere in your code you block the code (e.g. Thread.sleep, waiting for a socket, etc), your code will still block, because there is no other thread in the thread-pool to serve that blocking thread and allow the calling thread to suspend.
A
suspend fun
is like a callback:
suspend fun myFun(a: Int): String
==
fun myFun(a: Int, continuation: Continuation<String>): Any
🎉 2
When your
myFun
is done, the
continuation
, which is a fancy callback, is called with the resulting
String
callback value. The difference is with
suspend
, that your callback value is rewritten by the compiler to become a return value instead, allowing to write normal, imperative/sequential code instead of dealing with callbacks.
👍🏾 2
e

Evan R.

03/13/2020, 1:51 PM
What Anton said. I’ll add on and give you an idea of what happens step-by-step based on my understanding: 1. A suspending function is running. 2. Eventually, the suspending function hits a suspending function invocation. 3. The suspending function then adds the suspending function call to the job queue of the current dispatcher and passes the suspending function call a
Continuation
instance so when the suspending function returns the calling suspend function can be resumed from the point it left off. 4. The calling suspending function then stashes all its local variables in a state machine instance and the function is returned from. It is no longer running. 5. Eventually, the invoked suspending function will be dispatched from the dispatcher’s queue onto one of the threads it manages. 6. The suspending callee will eventually return and schedule the suspending caller using the continuation it received onto the dispatcher so the suspending caller can receive the return value. 7. The suspending caller eventually gets dispatched onto the thread pool again and resumes from where it left off, retrieving all its old state from its state machine.
I’m basing this off the deep-dive on coroutines talk from KotlinConf 2017, so if you want this from the source go ahead and check out the video:

https://youtu.be/YrrUCSi72E8

c

charlesmuchene

03/13/2020, 1:53 PM
Ah. Great. Checking out this one.
Much appreciated guys. I’ll be digesting these replies all day.
⏸️ 1
👍 1
l

Luis Munoz

03/13/2020, 3:11 PM
@Evan R. well said. What confused me though is how the concurrency works. If you suspend the local variables must be stored, when you resume you might be on another thread, how does the synchronization happen?
e

Evan R.

03/13/2020, 3:13 PM
The state machine which stores all the local variables is actually the continuation, having watched the video again. Thus when the dispatcher pops the suspending function call off the queue onto a different thread all the local state comes with it.
l

Luis Munoz

03/13/2020, 3:13 PM
In vertx you have verticles when you add something to the event loop you will always come back to the same event loop so there is no synchronization needed
the variables are references in the heap though, so they must be synchronized
you can't just pop them off the queue and expect them to work
e

Evan R.

03/13/2020, 3:13 PM
Yes but only one instance of the function call will be executing at a time so there’s no issue with concurrent modification
l

Luis Munoz

03/13/2020, 3:14 PM
when you are on another thread you can't guarantee you are looking at flushed out value if you don't synchronize
e

Evan R.

03/13/2020, 3:18 PM
Correct me if I’m wrong, but aren’t all objects on the JVM passed by reference? Therefore, wouldn’t the state machine be stashed on the heap and then accessed by a different thread when the coroutine resumes? It would be no more dangerous than the function modifying its own local variables
It’s not like any data copying between threads is occurring besides the pointer to the object on the heap
Either way, I assume the dispatcher ensures that the state machine data is fully flushed before rescheduling the coroutine
l

Luis Munoz

03/13/2020, 3:22 PM
@Evan R. yeah that is bad. each thread may be on another core. each cpu core has a different local cache so they see what is the heap slightly differently. you have to deliberately synchronize between threads so they see the same thing. @streetsofboston do you know how that works?
when it resumes there is a penalty to always synchronize right?
e

Evan R.

03/13/2020, 3:33 PM
I believe the dispatcher tries its best to keep a coroutine on the same thread but if it is not available then there would be a context switch and data transfer between the threads, yes
But at the same time if you wanted to fully avoid that you could use a single-threaded dispatcher. Coroutines are all about managing a large volume of work concurrently
@Luis Munoz for further information I’d recommend just checking out the implementation of the event loop, in particular: https://github.com/Kotlin/kotlinx.coroutines/blob/3592a8cf1a7da3bbd11967602d82ad9ebeb82f07/kotlinx-coroutines-core/common/src/EventLoop.common.kt#L252 for how the event queue is implemented and: https://github.com/Kotlin/kotlinx.coroutines/blob/3592a8cf1a7da3bbd11967602d82ad9ebeb82f07/kotlinx-coroutines-core/jvm/src/DefaultExecutor.kt#L60 for the Default Executor’s
Runnable
implementation which handles invoking the next task in the queue and parking until new coroutines come in
The queue is just a Java atomic, concurrent queue of Runnables (coroutines) which are popped off onto the thread
👍 1
Sorry for hijacking your thread @charlesmuchene lol
c

charlesmuchene

03/13/2020, 4:08 PM
Hahaha. Interesting conversation going on @Evan R.. Following…
3 Views