kotlinx.coroutines
kotlinx.coroutines copied to clipboard
Internal API to retreive a single CPU-bound task from Dispatchers.Default
IntelliJ IDEA platform has the following core API:
// In a blocking, non-suspendable world that is executed in ForkJoinPool
decompose() {
// here happens decomposition of the task and .join()
}
Such API is composable in a way that it is possible to call decompose recursively from within subtasks.
It may be tempting to rewrite it with coroutines in a following manner:
fun decompose() = runBlocking {
for (task in decomposition) {
launch(Dispatchers.Default) { task() }
}
}
The problem is -- this code is prone to both starvation and deadlocks -- each call to decompose from Dispatchers.Default occupies at least one thread in the backing executor for joinBlocking(), meaning that eventually, such code may deadlock.
It is not the case for the FJP-based solution, because .join on any FJP task not only awaits for the task to complete but also helps to execute subtasks if the joining thread is part of the target's FJP.
It doesn't seem that we can provide a full-blown FJP-like API out-of-the-box, but as the first steps we can provide an internal TBD API getSingleDispatchersDefaultTaskOrNull. With such API, it is possible to emulate decompose API and, after initial evaluation by the IDEA team, we may want to promote it to @Delicate API as one more way to bridge blocking calls with coroutine dispatchers.