Anubhav Bimbisariye
Anubhav Bimbisariye

Reputation: 41

Kotlin async await with limited parallelism

I am testing out a behaviour with kotlin where I want to make api calls corresponding to a list. I am using async await to make it asynchronous calls. Here's a piece of code to emulate that:

/**
 * You can edit, run, and share this code. 
 * play.kotlinlang.org 
 */
import kotlinx.coroutines.*

fun main() {
    val numList = (1..20).toList()
    //print(numList)
    runBlocking(Dispatchers.IO.limitedParallelism(5)){
        numList.map{
          async{delayed(it)}
        }.awaitAll()
    }
}

suspend fun delayed(number: Int):Int {
    print("$number Start")
    delay(1000)
    println("$number end")
    return number
    
}

Which I am trying on version 1.6.0+

the out put for this prints start for 1 -20 then end for 1-20 I want to control the parallelism here, I don't want to bombard the server with all the requests in one go. I want controlled asynchronicity.

With limited parallelism I have, I'd expect a response like starts for 1-5, ends for 1-5, starts of 5-10, ends of 5-10... starts of 15-20, ends of 15-20

However it is still starts of 1-20 ends of 1-20. limited parallelism it seems controls the number of threads this will use. Any idea on how I can go on about achieving control here?

Upvotes: 3

Views: 1696

Answers (1)

broot
broot

Reputation: 28332

You limited paralellism here, but what you need is to limit concurrency. These two words are related, but they mean different things. The difference was explained here: What is the difference between concurrency and parallelism?

To limit the concurrency, you need to use synchronization utils and the easiest in your case is to use a semaphore:

val semaphore = Semaphore(5)
numList.map{
    async {
        semaphore.withPermit {
            delayed(it)
        }
    }
}.awaitAll()

You can remove limitedParallelism(5), it is not needed.

Alternatively, we can create a queue of tasks (Channel) and launch 5 coroutines that will consume items from it. It provides a little more control over the process and if we plan to queue huge number of tasks (like tens of thousands) then it may be better for performance to keep a queue of tasks than launching thousands of coroutines. But in your case a semaphore seems like a better approach as it is simpler.

Upvotes: 5

Related Questions