In the coroutines guide there are a lot of good examples; unfortunately, they’re fairly contrived. Specifically, none of them really demonstrate blocking (but non-CPU-bound) calculations.
Let’s suppose you want to make ProcessBuilder more coroutine-friendly, while fully taking advantage of parallelism. Might such a solution look like the following?
class ProcessExecutor(private val executor: Executor) {
suspend fun execute(processBuilder: ProcessBuilder): Int =
CompletableFuture.supplyAsync(Supplier {
Thread.sleep(1000) // simulating a slow command
processBuilder.start().waitFor()
}, executor).await()
}
fun main(args: Array<String>) {
val executor = Executors.newFixedThreadPool(4)
runBlocking {
val processBuilder = ProcessBuilder("cmd", "/C", "dir")
.inheritIO()
val result = ProcessExecutor(executor)
.execute(processBuilder)
println("Result: $result")
}
executor.shutdown()
}
Is this the best way to do this? If so, it raises a couple interesting points. One is you actually need two threadpools (er, executors) – one for doing the non-coroutine work (where CompletableFutures get submitted), and another for the coroutines, though you might use CommonPool
. Correct?
Another question/point – as far as I can tell, submitting futures to threadpools and await
ing them seems by far the most pragmatic way of integrating with blocking code. Is that correct, or is there another, possibly better way to accomplish the same thing?