hey got a question about the suspension point of c...
# coroutines
r
hey got a question about the suspension point of channels. Given the following code snipet
Copy code
class SimpleChannelTest {
    val simpleChannel = Channel<Int>()

    fun simpleFunction() {
        runBlocking {
            launch {
                simpleChannel.consumeEach { println(it) }
            }

            var x = 0

            repeat(10) {
                simpleChannel.send(x++)
                println("sent Message")
            }
            simpleChannel.close()

        }
    }
I would expect each time send is called , the main coroutine will suspend until the data is received, however I end up with this as the result
Copy code
0
sent Message
sent Message
1
2
sent Message
sent Message
3
4
sent Message
sent Message
5
6
sent Message
sent Message
7
just wondering why this is?
s
Well,
send
only has to suspend until another coroutine calls
receive
. If another coroutine is already waiting to receive an item, then after
send
is called, both coroutines are actually eligible to be resumed right away. The sender can resume immediately because
receive
has been called, and the receiver can resume because
send
has been called. It's down to the dispatcher to decide which one gets resumed first. If the dispatcher had more than one thread, they would end up running in parallel.
n
It's down to the dispatcher to decide which one gets resumed first.
That's not quite accurate. If something is waiting to
receive
, then
send
doesn't suspend at all, so the dispatcher isn't involved. Here's the code (offerInternal is basically
trySend
):
Copy code
public final override suspend fun send(element: E) {
        // fast path -- try offer non-blocking
        if (offerInternal(element) === OFFER_SUCCESS) return
        // slow-path does suspend or throws exception
        return sendSuspend(element)
    }
In general, I've noticed suspend methods don't actually suspend if they don't have to. This can lead to subtle bugs if they are called in a loop and happen to not suspend such that they block the thread, like if you
send
to a
Channel
created with
Channel.UNLIMITED
.
s
Good clarification, thank you!
r
Thank for that. Makes sense
Although it does still suspend. Just not at the send function. Atleast thats what i see
n
Coroutines are co-operative, they can't just suspend anywhere. You have to actually give up control of the thread. What you are seeing is the effect of the single threaded dispatching.
send
does not suspend when a
receive
is in progress, but then the next time
send
is called, it does suspend, because it's had control of the thread, so the
receive
loop has not had a chance to run, so
send
suspends, and then the next call to
receive
does not suspend because
send
is in progress and then it calls
receive
again which suspends because it's had control of the thread so the
send
loop has not been able to run.
r
mind blown
I get it, now it makes sense . thanks for the explanation !