rkeazor
03/23/2022, 4:22 AMclass 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
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?Sam
03/23/2022, 8:52 AMsend
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.Nick Allen
03/23/2022, 5:14 PMIt'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
):
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
.Sam
03/23/2022, 5:16 PMrkeazor
03/23/2022, 5:46 PMrkeazor
03/23/2022, 5:52 PMNick Allen
03/23/2022, 5:59 PMsend
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.rkeazor
03/24/2022, 6:09 AMrkeazor
03/24/2022, 6:09 AM