I'm working on a project that involves computationally intensive tasks that I want to run in parallel. To do so, I'm using multiple async
statements to run the tasks and awaitAll
to wait until all threads completed computation.
suspend fun tasks() {
coroutineScope {
val result = List (10) {
async {
// do stuff
}
}.awaitAll()
}
}
My question is how to bridge between this code that is run in parallel and regular synchronous code.
I tried to use runBlocking
but that seems to run all the async
tasks after one another, therefore defeating the whole purpose of using coroutines. The only way I got it to work was to use suspend
functions all the way up to the main
function, however that is not suitable in my case, as I rely on third-party libraries to call my code from regular functions.
Is there a way to call suspend functions from regular functions while still maintaining their ability to run in parallel?
CodePudding user response:
The reason why subtasks were running sequentially is that by default runBlocking()
utilizes the thread that invoked it to create a single-thread dispatcher and runs all coroutines using it. If your coroutines never suspend, they will be invoked sequentially.
In order to use another dispatcher, we simply need to pass it to runBlocking()
:
runBlocking(Dispatchers.Default) { ... }
However, if you don't use coroutines already and you don't plan to suspend, but only perform CPU-intensive tasks, then I'm not sure if you can at all benefit from coroutines. Coroutines are mostly for performing tasks that often have to wait for something, so we can utilize their suspend & resume feature. They are useful, if we need to often fork and join. But if we simply need to parallelize CPU computation, then the classic approach with executors will do.
Also, when bridging using runBlocking()
, be careful to not invoke it from the coroutine itself. We can't block the thread while running inside the coroutine context. It could cause serious performance problems or even a deadlock. If you invoke runBlocking()
, and then inside it, somewhere deep into the call stack, you invoke one of your bridges again, you will run into problems.