DEV Community

Khoa Pham
Khoa Pham

Posted on

Understanding suspend function in Kotlin Coroutine

Getting to know Coroutine

From https://kotlinlang.org/docs/reference/coroutines.html

To continue the analogy, await() can be a suspending function (hence also callable from within an async {} block) that suspends a coroutine until some computation is done and returns its result:

From https://kotlinlang.org/docs/tutorials/coroutines-basic-jvm.html

We are using the delay() function that's like Thread.sleep(), but better: it doesn't block a thread, but only suspends the coroutine itself. The thread is returned to the pool while the coroutine is waiting, and when the waiting is done, the coroutine resumes on a free thread in the pool.

await() can not be called outside a coroutine, because it needs to suspend until the computation finishes, and only coroutines can suspend in a non-blocking way

What does suspend function mean in Kotlin Coroutine 🤔

https://stackoverflow.com/questions/47871868/what-does-suspend-function-mean-in-kotlin-coroutine

Understanding async

From https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md

Conceptually, async is just like launch. It starts a separate coroutine which is a light-weight thread that works concurrently with all the other coroutines. The difference is that launch returns a Job and does not carry any resulting value, while async returns a Deferred -- a light-weight non-blocking future that represents a promise to provide a result later. You can use .await() on a deferred value to get its eventual result, but Deferred is also a Job, so you can cancel it if needed.

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

There is a laziness option to async using an optional start parameter with a value of CoroutineStart.LAZY. It starts coroutine only when its result is needed by some await or if a start function is invoked. Run the following example that differs from the previous one only by this option:

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
        val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

What is the difference between launch/join and async/await in Kotlin coroutines

https://stackoverflow.com/a/48079738/1418457

I find this guide https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md to be useful. I will quote the essential parts

🦄 coroutine

Essentially, coroutines are light-weight threads.

So you can think of coroutine as something that manages thread in a very efficient way.

🐤 launch

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

So launch starts a background thread, does something, and returns a token immediately as Job. You can call join on this Job to block until this launch thread completes

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // wait until child coroutine completes
}

🦆 async

Conceptually, async is just like launch. It starts a separate coroutine which is a light-weight thread that works concurrently with all the other coroutines. The difference is that launch returns a Job and does not carry any resulting value, while async returns a Deferred -- a light-weight non-blocking future that represents a promise to provide a result later.

So async starts a background thread, does something, and returns a token immediately as Deferred.

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

You can use .await() on a deferred value to get its eventual result, but Deferred is also a Job, so you can cancel it if needed.

So Deferred is actually a Job. See https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html

interface Deferred<out T> : Job (source)

🦋 async is eager by default

There is a laziness option to async using an optional start parameter with a value of CoroutineStart.LAZY. It starts coroutine only when its result is needed by some await or if a start function is invoked.

Original post https://github.com/onmyway133/blog/issues/123

Top comments (0)