Search code examples
kotlinkotlinx.coroutineskotlin-coroutines

How to delay within async function that returns Deferred<T>


I have below kotlin coroutine code. doWorkAsync is normal (non suspend) function and it returns Deferred<Int>.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val result = doWorkAsync("Hello ")
}

fun doWorkAsync(msg: String): Deferred<Int>  = async {
    log("$msg - Working")
    delay(500)
    log("$msg - Work Done")
    return@async 42
}

fun log(msg: String ) {
    println("$msg in ${ Thread.currentThread().name }")
}

I don't know how to use delay within doWorkAsync function.

I'm using kotlin coroutines version kotlinx-coroutines-core:1.1.1.


Solution

  • You need to specify a scope:

    fun doWorkAsync(msg: String) = GlobalScope.async {
        log("$msg - Working")
        delay(500)
        log("$msg - Work Done")
        return@async 42
    }
    

    This way, inside your lambda, you will have a CoroutineScope.

    Note: Since you are using an expression body, you don't need to specify the return type Deferred<Int> explicitely. It can be inferred.


    A more flexible solution using a suspended function

    But there is an even better way. I mean in this context it is obvious that the function should be async. But what if you want a function that can be called asynchronous and sequentially?

    That's where suspending functions come into play. You define your function like this:

    suspend fun doWork(): Int {
        // ...
        delay(500)
        // ...
        return 42
    }
    

    An then you can decide at call-site how you want to use it:

    val d: Deferred<Int> = GlobalScope.async { doWork() } // asnyc
    val i: Int = runBlocking { doWork() } // sequential