arg20
arg20

Reputation: 4991

Kotlin: Create custom CoroutineContext

I'm using Kotlin in my API backend. I don't want to run db queries in the common pool. Basically, I want to create a CoroutineContext that has a number of threads that matches the database maximumPoolSize.

What's the best way to accomplish this (generally and for my specific use case)? I know Kotlin provides contexts out of the box, but what's the best approach to create my own?

Bonus question: If I have a jdbc connection pool size of 3, does it make sense to use a coroutinecontext with a thread pool size of 3? Can this guarantee the best concurrency possible?

Upvotes: 3

Views: 3883

Answers (3)

GenError
GenError

Reputation: 1186

The answer by zsmb13 works perfectly, but Android Studio warns that newFixedThreadPoolContext is a delicate API and should only be used in specific cases.

The recommended alternative (as of Spring 2022) for limited parallelism is limitedParallelism:

Creates a view of the current dispatcher that limits the parallelism to the given value. The resulting view uses the original dispatcher for execution, but with the guarantee that no more than parallelism coroutines are executed at the same time.
This method does not impose restrictions on the number of views or the total sum of parallelism values, each view controls its own parallelism independently with the guarantee that the effective parallelism of all views cannot exceed the actual parallelism of the original dispatcher.

(from https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/limited-parallelism.html)

So an alternative solution would be to create a view on the thread pool used for the db connection like:

val dbDispatcher = Dispatchers.IO.limitedParallelism(maximumPoolSize)

and then use this as coroutine dispatcher.

Upvotes: 1

mantono
mantono

Reputation: 923

The function newFixedThreadPoolContext is now considered obsolete with current version of Kotlin coroutines (1.3.0), as it is now annotated with @ObsoleteCoroutinesApi and it will give you a warning if you would try to use. The documentation also states that it will be replaced in the future.

The recommended way to create a CoroutineContext is now through

Executors.newFixedThreadPool(3).asCoroutineDispatcher()

So a complete example with imports, where also creating a CoroutineScope, would look like this

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors
import kotlin.coroutines.CoroutineContext

fun coroutineScope(threads: Int): CoroutineScope {
    val context: CoroutineContext = Executors.newFixedThreadPool(threads).asCoroutineDispatcher()
    return CoroutineScope(context)
}

Upvotes: 6

zsmb13
zsmb13

Reputation: 89568

You can create a CoroutineContext that's backed by a thread pool with a fixed number of threads using newFixedThreadPoolContext:

val myContext = newFixedThreadPoolContext(nThreads = 3, name = "My JDBC context")

And yes, it seems like a good idea to match your thread pool's size to the connection pool's size, because that way your threads (assuming they each use one connection at a time) will always have a database connection ready for them - here's a blog post suggesting the same.

Upvotes: 5

Related Questions