Reputation: 105220
Suppose I have a blocking function because of some third party library. Something along these lines:
fun useTheLibrary(arg: String): String {
val result = BlockingLibrary.doSomething(arg)
return result
}
Invocations to BlockingLibrary.doSomething
should run on a separate ThreadPoolExecutor
.
What's the proper way (assuming there is a way) of achieving this with kotlin?
Note: I've read this thread but seems pretty outdated
Upvotes: 10
Views: 3479
Reputation: 93609
If the blocking code is blocking because of CPU use, you should use Dispatchers.Default
. If it is network- or disk-bound, use Dispatchers.IO
. You can make this into a suspending function and wrap the blocking call in withContext
to allow this function to properly suspend when called from a coroutine:
suspend fun useTheLibrary(arg: String): String = withContext(Dispatchers.Default) {
BlockingLibrary.doSomething(arg)
}
If you need to use a specific ThreadPoolExecutor
because of API requirements, you can use asCoroutineDispatcher()
.
val myDispatcher = myExecutor.asCoroutineDispatcher()
//...
suspend fun useTheLibrary(arg: String): String = withContext(myDispatcher) {
BlockingLibrary.doSomething(arg)
}
If your library contains a callback-based way to run the blocking code, you can convert it into a suspend function using suspendCoroutine()
or suspendCancellableCoroutine()
. In this case, you don't need to worry about executors or dispatchers, because it's handled by the library's own thread pool. Here's an example in the Retrofit library, where they convert their own callback-based API into a suspend function.
Upvotes: 11