I am complete new to Kotlin so please bear with me. My problem: I am developing an API that will query a database. The database provides JDBC connector that is blocking and my queries will be long-running (up to 60s). Is it possible to turn the blocking code into non-blocking with Kotlin? How? Example code would be appreciated. Thanks.
Well, yes and no. We can’t anyhow turn blocking operation into non-blocking. But we can handle it in a smart way, so most of our code is non-blocking.
While using Kotlin coroutines, we can do it simply by:
with (Dispatchers.IO) {
// blocking operation
}
Internally, it schedules the operation using a special thread pool, but the calling thread is only suspended and can do something else.
If not using coroutines then I believe Kotlin doesn’t provide any tools for this.
Do you mean withContext(...)
?
Yes, I meant withContext()
It is not possible to turn blocking code into a non-blocking. Unless project Loom fulfills its promise and even in this case it probably won’t be fully automatic. In Kotlin you can call blocking code asynchronously. Though it will still block a thread it is called on.
Yeah basically what broot and thumannw said; use withContext()
.
Let’s say your blocking database call looks like this:
database.withHandle { it.createQuery("get-my-data.sql").list() }
Put that code inside a withContext
lambda, like so:
withContext(Dispatchers.IO) {
database.withHandle { it.createQuery("get-my-data.sql").list() }
}
This will run the code inside the withContext
lambda on the Dispatchers.IO coroutine dispatcher; essentially what happens is your blocking code is run on a different thread, while your calling thread is suspended while waiting for the blocking code to complete. It doesn’t stop the blocking code from blocking a thread, but since it blocks a thread in a threadpool and suspends your calling thread, you still get the effect you want.
If you want to make it more dynamic, and allow consumers of your API to provide their own threadpool/dispatcher for running blocking code, you could do something like the following:
suspend fun <T> makeBlockingCodeSuspend(
dispatcher: CoroutineDispatcher? = null,
block: suspend CoroutineScope.() -> T
) = withContext(dispatcher ?: Dispatchers.IO, block)
EDIT: Anyone know how to make Dispatchers.IO not show up as a hyperlink?
Like this: Dispatchers.IO