Gerardo Epitacio
08/08/2023, 6:13 AM_runBlocking_(<http://Dispatchers.IO|Dispatchers.IO>)
, not totally sure if this is the way to go, seem like not.
Adding a little more explanation:
1. Kotlin creates a couple( 400 ) coroutines with async coroutines builder, which executes some operations in async using async coroutine builder
2. The created coroutine call some complex Java code that requires to do some database operations, that’s why I need to call a regular Kotlin method and that regular Kotlin method calls the room function with a valid coroutine scope create with runBlocking.
3. Doing a Thread Dump visualization I got something like the shared picture.
Note: All flow of my program works just fine if I lunch around 50 coroutines (I did a test with that amount), but seems like more than one hundred causes the hang.xoangon
08/08/2023, 6:21 AMCoroutineScope
that you could be generating for that case.
As the Kotlin function is not suspend
, you shouldn’t have any problem on calling it from JavaGerardo Epitacio
08/08/2023, 6:48 AMGerardo Epitacio
08/08/2023, 6:51 AM// creates around 400 coroutines with async
override suspend fun executeExpressions() {
val expressionSize = this.expressions.size
val expressionsToExecute: List<FxlExpression> = this.expressions.values.toList()
val result: List<Deferred<String>> = expressionsToExecute.mapIndexed { index, expressionObject ->
async {
println("Expression ($index/$expressionSize) ${expressionObject.key} started")
// calls Java code as part of the operation logic.
val result: String? = executeExpression(expressionObject.key, expressionObject.value)
println("Expression ($index/$expressionSize) ${expressionObject.key} finished")
"Expression ($index/$expressionSize) ${expressionObject.key} result $result"
}
}
val result = result.awaitAll()
}
Gerardo Epitacio
08/08/2023, 6:53 AM// called from Java code that calls a suspend function
@Synchronized
@Expe`rimentalCoroutinesApi`
override fun executeBehavior(evaluator: Evaluator, behaviorKey: String): Boolean {
return _runBlocking_(this.dispatcher) *{*
// suspend Room database methods.
}
}
xoangon
08/08/2023, 6:59 AMxoangon
08/08/2023, 7:02 AMrunBlocking(<http://Dispatchers.IO|Dispatchers.IO>)
is the right choice. If this latter is your case, you can still take a look at the project Loom virtual threads in JavaGerardo Epitacio
08/08/2023, 7:02 AMGerardo Epitacio
08/08/2023, 7:04 AMxoangon
08/08/2023, 7:10 AMCoroutineScope
context comes from that allows you to call the async
function?
Are you creating your own implementation of CoroutineScope
extending from the interface?Gerardo Epitacio
08/08/2023, 7:27 AMGerardo Epitacio
08/08/2023, 7:40 AMGerardo Epitacio
08/08/2023, 7:45 AMxoangon
08/08/2023, 7:46 AMCoroutineScope
for a case like this. Using coroutineScope
as in this last example is the correct approach.
That is an improvement but not the root cause of your problem. You should call the executeExpression
suspend function in a CoroutineScope
instance instead of inside the runBlocking
scope. This latter one will be blocking threads and you may not be able to launch 400 blocking coroutines. You could instead use GlobalScope.launch { }
or create your own CoroutineScope
instance using the CoroutineScope()
factory functionGerardo Epitacio
08/08/2023, 7:46 AMxoangon
08/08/2023, 7:46 AMGerardo Epitacio
08/08/2023, 7:48 AMprivate val supervisor: CompletableJob = _SupervisorJob_()
private val coroutineScope = _CoroutineScope_(supervisor)