Migrating to Kotlin 1.5, I've stumbled upon an issue with the Channel's new trySendBlocking()
method.
So, we have an actor returning a SendChannel<Command>
, Command
being our own data class.
When sending commands to the actor in Kotlin 1.4, we used to use its channel like this:
channel.sendBlocking(command)
Now, it's advised to use the following in Kotlin 1.5:
channel.trySendBlocking(command)
Fine, but then I'm wondering why not use trySend()
instead of trySendBlocking()
?
Some things I'm scratching my head about:
If we are sure that the capacity of the channel is big enough, and that the actor is consuming it fast enough, then the channel won't get full and
trySend()
will always succeed. We could do something like this just to address the few cases where the channel might be full:do { val result = channel.trySend(command) } while (result.isFailure)
The
trySendBlocking()
internally usesrunBlocking()
which blocks the whole thread. According to the documentation,runblocking()
is "designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests". But here it's used in a way that is outside of this documented use case. It might block the whole thread. I would have thought this was a bad idea?Is
trySend()
thread safe? If several threads calltrySend()
simultaneously on the same channel, could there be troubles? Is that the reason we prefertrySendBlocking()
?
Thanks
Maybe you want to use send() method instead?
As I understand, this is exactly the case authors meant. This method is synchronous and should be used with blocking code. If it was not available, to bridge the synchronous code with asynchronous, you would use runBlocking method.
After a quick look inside, to me looks like thread-safe; it uses atomic variables and other concurrency-related stuff, but as not a designer of these, I can't confirm for sure. Actors supposed to be thread-safe.