tyczj
tyczj

Reputation: 73721

Coroutines not running in parallel

I have a few suspend functions that make a network call in my WorkManager that I am trying to get to run in parallel using Coroutines so I was trying to use async in them but they seem to still be executed sequentially.

Example:

suspend fun call1() = withContext(Dispatchers.IO){
    async{
        Log.d(TAG,"Call 1 started")
        delay(2000)
        Log.d(TAG,"Call 1 fiished")
    }
}

suspend fun call2() = withContext(Dispatchers.IO){
    async{
        Log.d(TAG,"Call 2 started")
        delay(5000)
        Log.d(TAG,"Call 2 finished")
    }
}

suspend fun call3() = withContext(Dispatchers.IO){
    async{
        Log.d(TAG,"Call 3 started")
        delay(1000)
        Log.d(TAG,"Call 3 finished")
    }
}

I call them like this

override suspend fun doWork(): Result{
    setForeground(createForegroundInfo())
    call1()
    call2()
    call3()
    return Result.success()
}

When I run this I see the log messages show up as in order just as they are called and the next call does not start until the previous one finishes. What I was expecting is call3 to finish first then call1 and finally call2 but it just gets call1, call2, call3.

What am I missing to get these to execute in parallel?

Upvotes: 2

Views: 1316

Answers (1)

aminography
aminography

Reputation: 22832

If you create a new scope for each one, they would be launched in parallel:

suspend fun call1() = CoroutineScope(Dispatchers.IO).launch {
    Log.d(TAG, "Call 1 started")
    delay(2000)
    Log.d(TAG, "Call 1 fiished")
}

Update:

Although the above solution works in parallel, but you can not keep track of the coroutines which causes a possible execution leak. To preserve structural concurrency it's better to do it like the following:

suspend fun call1() = withContext(Dispatchers.IO) {
    Log.d(TAG, "Call 1 started")
    delay(2000)
    Log.d(TAG, "Call 1 fiished")
}

suspend fun call2() = withContext(Dispatchers.IO) {
    Log.d(TAG, "Call 2 started")
    delay(5000)
    Log.d(TAG, "Call 2 finished")
}

suspend fun call3() = withContext(Dispatchers.IO) {
    Log.d(TAG, "Call 3 started")
    delay(1000)
    Log.d(TAG, "Call 3 finished")
}

And then:

override suspend fun doWork(): Result{
    setForeground(createForegroundInfo())

    coroutineScope {
        launch { call1() }
        launch { call2() }
        launch { call3() }
    }
    Log.d(TAG, "After all finishings")

    return Result.success()
}

Upvotes: 3

Related Questions