question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add priority hint for CoroutineDispatchers

See original GitHub issue

It will be useful for the tasks which depend on the quality of service. For example, we have N abstract clients using the common thread pool via CoroutineDispatcher. In rare moments a few clients have tasks with high priority to execution and they should be computed as soon as possible. Note: If we create multiple pools for each priority, the situation will turn out that if there are no tasks with a certain priority, some pools will be idle while others may be overloaded.

I guess, that the problem can be solved like that:

  1. Create new CoroutineContextElement (for example, CoroutinePriority);
  2. If CoroutinePriority is provided by CoroutineContext, wrap a dispatched task into an object which can be compared by taken priority and put it into the executor.

The new context element can thus be used:

launch(Dispatchers.Default + CoroutinePriority(42)) {
    ...
}

The element behaves like a hint. It works only in cases when the dispatcher created from custom thread pool with PriorityQueue and the priority is provided by context, so it produces no overhead in the other cases.

Unfortunately, the most of classes related with Dispatchers are internal in the coroutines package, so it isn’t possible to create this logic outside the coroutines library without pain. The another possible solution is to provide the extended API.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
elizarovcommented, Oct 17, 2019

You don’t really need to maintain all the internals. Look, a dispatcher implementation can be as simple as that:

class MyDispatcher : CoroutineDispatcher() {
    private val executor = Executors.newCachedThreadPool() // or anything else

    override fun dispatch(context: CoroutineContext, block: Runnable) =
        executor.execute(block)
}
0reactions
Richie94commented, Feb 18, 2022

Hey, Im having the same request and wanted to have on one hand some validation that this is how it should be written and on the other hand to have some online example to copy.

class PriorityExecutor {

    private val priorityDispatcher = PriorityDispatcher()

    internal class PriorityDispatcher : CoroutineDispatcher() {

        private val priorityExecutor = ThreadPoolExecutor(
            1, 1, 0L, TimeUnit.MILLISECONDS, PriorityBlockingQueue(100000),
            CustomizableThreadFactory("importRunner-serializer")
        )

        override fun dispatch(context: CoroutineContext, block: Runnable) {
            val priority = context[CoroutinePriority]?.priority ?: 0
            val executable = RunWithPriorityFuture(RunWithPriority(block, priority))
            priorityExecutor.execute(executable)
        }

    }

    internal data class CoroutinePriority(
        val priority: Int
    ) : AbstractCoroutineContextElement(CoroutinePriority) {
        companion object Key : CoroutineContext.Key<CoroutinePriority>

        override fun toString(): String = "CoroutinePriority($priority)"
    }

    internal class RunWithPriority(val runnable: Runnable, val priority: Int) : Runnable {

        override fun run() {
            runnable.run()
        }
    }

    internal class RunWithPriorityFuture(private val runWithPriority: RunWithPriority) :
        FutureTask<RunWithPriorityFuture>(runWithPriority.runnable, null), Comparable<RunWithPriorityFuture> {

        override fun compareTo(other: RunWithPriorityFuture): Int {
            return other.runWithPriority.priority - runWithPriority.priority
        }

    }

    fun submitAction(priority: Int, runnable: suspend () -> Unit): Job {
        return CoroutineScope(priorityDispatcher).launch(CoroutinePriority(priority)) {
            runnable.invoke()
        }
    }
}

is this the way @elizarov you would do it? The priorityqueue/threadexecutor under the hood is taken from java examples, I just want to be able to also run suspending functions when I call it

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to set thread priority of a coroutine dispatcher in Kotlin ...
I'm thinking about writing a custom dispatcher using dispatch_queue, but it seems to be a non-trivial task. So any help to find an...
Read more >
Improve app performance with Kotlin coroutines
Kotlin coroutines use dispatchers to determine which threads are used for coroutine execution. To run code outside of the main thread, ...
Read more >
Coroutine context and dispatchers - Kotlin
The coroutine context includes a coroutine dispatcher (see CoroutineDispatcher) that determines what thread or threads the corresponding ...
Read more >
Coroutines Dispatchers.Default and Dispatchers.IO ...
My argument against Kotlin Coroutines' default background dispatchers: Dispatchers.Default and Dispatchers.IO.
Read more >
Android Coroutine Recipes. Table of Contents - ProAndroidDev
Coroutine dispatcher · uiDispatcher to dispatch execution onto the Android main UI thread (for the parent coroutine). · bgDispatcher to dispatch execution in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found