https://kotlinlang.org logo
#getting-started
Title
# getting-started
s

Stefan Oltmann

09/29/2023, 7:54 AM
Since I don't see a default PriorityChannel I tried to build my own, but I fail to see how I can get rid of the call to
delay
👀... I want a fixed amount of coroutines working on my job and I have high priority requests that should be worked on first and low priority requests that can be done later. I don't think my implementation is good. What would be a good implementation of my goal here? It must be Multiplatform.
Copy code
private val CONCURRENT_WORKERS = PROCESSOR_COUNT * 2

private val WORKER_COROUTINE_SCOPE = CoroutineScope(Dispatchers.Default)

private val channel = Channel<Pair<Photo, CompletableDeferred<PhotoMetadata>>>()

private val queue = ArrayDeque<Pair<Photo, CompletableDeferred<PhotoMetadata>>>()

private val mutex = Mutex()

init {

    /**
     * Run as many coroutines for parallel execution as we need.
     */
    repeat(CONCURRENT_WORKERS) {
        WORKER_COROUTINE_SCOPE.launch(CoroutineName("MetadataReader-$it")) {

            for (work in channel)
                readAndSaveMetadataInternal(work)
        }
    }

    /**
     * This coroutine gets the next photo from the list and sends
     * it to the channel.
     */
    WORKER_COROUTINE_SCOPE.launch(CoroutineName("MetadataReaderFeeder")) {

        while (true) {

            val next = mutex.withLock { queue.removeFirstOrNull() }

            /* Nothing to do right now. Check back later. */
            if (next == null) {
                delay(500)
                continue
            }

            channel.send(next)
        }
    }
}

override suspend fun readAndSaveMetadata(photo: Photo, withPriority: Boolean): PhotoMetadata {

    val deferred = CompletableDeferred<PhotoMetadata>()

    mutex.withLock {

        if (withPriority)
            queue.addFirst(photo to deferred)
        else
            queue.addLast(photo to deferred)
    }

    return deferred.await()
}
3
s

Sam

09/29/2023, 8:07 AM
Why not have two channels, one for the high priority tasks and one for the low priority tasks? You can use
select
to receive from both channels at once, giving preference to the high-priority channel.
1
s

Stefan Oltmann

09/29/2023, 8:11 AM
I wasn't aware of select. Thank you, will try that.
Specifically I wasn't aware that
select
is biased in priority towards the first call. There is also a
selectUnbiased
. So that's what I wanted. Thank you again.
🍻 1