Dmytro Serdiuk
01/16/2024, 2:46 PMCancels reception of remaining elements from this channel with an optional cause. This function closes the channel and removes all buffered sent elements from it.
it’s just close with cancellation exception with removal of buffered items.
But calling *close*() will not trigger any exceptions for suspended *send*(), what is correct according to documentation:
Closing a channel after this function has suspended does not cause this suspended send invocation to abort, because closing a channel is conceptually like sending a special "close token" over this channel. All elements sent over the channel are delivered in first-in first-out order. The sent element will be delivered to receivers before the close token.
Could somebody explain me this cancel method please?Sam
01/16/2024, 3:50 PMclose()
method is part of the SendChannel
interface, and is designed to be used by producers that are delivering values to the channel. It signals that the producer won't send any more values. But any values that have already been sent, or that are in the process of being sent, will still be delivered.
The cancel()
method is part of the ReceiveChannel
interface, and is designed to be used by consumers that are receiving values from the channel. It signals that the consumer has gone away and won't consume any more values. It discards any values that haven't yet been received, because there would be no way to continue delivering values when there's no consumer to receive them.Sam
01/16/2024, 3:50 PMDmytro Serdiuk
01/16/2024, 3:53 PMval t = Channel<Int>(capacity = 0) { element ->
println("Clean up element ${element}")
}
fun main() = runBlocking<Unit> { //sampleStart
withTimeout(500) {
val s = launch(newSingleThreadContext("S Coroutine")) {
println("I'm inside === ${Thread.currentThread()}")
delay(50)
println("Before send === ${Thread.currentThread()}")
try {
t.send(4)
} catch(e: Throwable) {
println("Send finished with ${e} === ${Thread.currentThread()}")
println(t.isClosedForReceive)
}
println("Finished send")
}
launch(newSingleThreadContext("Cancel Coroutine")) {
println("Before cancel === ${Thread.currentThread()}")
delay(90)
println("Will cancel === ${Thread.currentThread()}")
t.cancel()
println(t.isClosedForSend)
}
launch(newSingleThreadContext("Check Coroutine")) {
println("Before receive delay === ${Thread.currentThread()}")
delay(150)
println("Before receive === ${Thread.currentThread()}")
try {
val value1 = t.receive()
println("Receive finished with ${value1} === ${Thread.currentThread()}")
println(t.isClosedForReceive)
} catch(e: Throwable) {
println("Receive finished with ${e} === ${Thread.currentThread()}")
}
println("Received finished === ${Thread.currentThread()}")
}
}
//sampleEnd
}
cancel will make send() to throw CancellationExceeption, but close will not and value would be delivered.
According to docs cancel use close and remove buffered elements, but why the behaviour is different?
ThanksSam
01/16/2024, 4:01 PMcancel()
actually calls close()
internally. When the docs say that cancel "closes" the channel, I think that just means that it puts the channel into a "closed" state. That means that, for example, isClosedForSend
will return true
and new attempts to send
will fail. Both close()
and cancel()
put the channel into this state, but they do it in different ways.Dmytro Serdiuk
01/16/2024, 4:02 PM