I have this requirement for a function that gets called periodically:
1. Get some input
2. Do 8 independent computations based on the input
3. Merge the results from these 8 computations and output the merged result
Since I've got at least 8 processors, I can do the 8 independent computations in parallel. So I created the following function:
fun process(in: InputType): ResultType {
runBlocking(Dispatchers.Default) {
val jobs = in.splitToList().map { async { processItem(it) } }
return jobs.awaitAll()
}
}
However, I've read in the documentation of runBlocking that it is "to be used in main functions and in tests."
This function is not the main function but is called way down in the call hierarchy in an application that does not otherwise use coroutines anywhere else.
What should I use to achieve this requirement if I shouldn't use runBlocking?
CodePudding user response:
This answer is probably a little opinionated and I may get downvoted, but I think there is nothing wrong in using runBlocking()
like this. The main point is to not overuse runBlocking()
as a cheap way to convert regular code into coroutine one. When converting to coroutines, it may be tempting to just put runBlocking()
everywhere in our code and that's all. This would be wrong, because it ignores structured concurrency and we risk blocking threads that should not be blocked.
However, if our whole application is not based on coroutines, we just need to use them in some place and we never need to cancel background tasks, then I think runBlocking()
is just fine.
Alternative is to create CoroutineScope
and keep it in some service with clearly defined lifecycle. Then we can easily manage background tasks, cancel them, etc.