Gilles Barbier
09/23/2024, 1:49 PMsuspend fun sendMessage(total: Int) = coroutineScope {
repeat(total) {
launch {
println("sending $it")
internalSendToAsync(it).await() // internalSendToAsync is a function returning a CompletableFuture
println("sent $it")
}
}
}
Then in my tests, everything works fine (I see 1000 "sending" and 1000 "sent") when I do:
sendMessage(1000)
But if I do:
CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
sendMessage(1000)
}.join()
Then I can see 1000 "sending $it" but 0 "sent $it". I have 64 starts of the fun internalSendToAsync
. I understand that I have all threads stuck in those calls, but I do not understand why, especially as it works for a simple call.
Even more strange: everything works fine again if I do this:
sendMessage(1000)
CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>).launch {
sendMessage(1000)
}.join()
Any hint about what could be the issues?Dmitry Khalanskiy [JB]
09/23/2024, 2:09 PMinternalSendToAsync(it)
with async { delay(100) }
, does the code behave like you expect? Maybe internalSendToAsync
is not prepared to handle multithreading. When you write sendMessage(1000)
in your tests, I assume you mean you use runTest { }
? In that case, everything happens on just one thread.Gilles Barbier
09/23/2024, 2:20 PMinternalSendToAsync
is not a suspendable function. It's a "normal" function asynchronously sending a message into a queue.Gilles Barbier
09/23/2024, 2:30 PMinternalSendToAsync
may create some sort of locking when initializedDmitry Khalanskiy [JB]
09/23/2024, 2:31 PMsuspend fun sendMessage(total: Int) = coroutineScope {
newSingleThreadContext("thread").use { ctx ->
repeat(total) {
launch {
println("sending $it")
withContext(ctx) {
internalSendToAsync(it).await()
}
println("sent $it")
}
}
}
}
This way, all internalSendToAsync
invocations will be on just one thread.Gilles Barbier
09/23/2024, 2:56 PM