Kotlin Training Program

DOWNLOAD APP

FEEDBACK

Async await

Introduction

Along with launch(), Kotlin provides one more Coroutine builder - async() function.

 
launch {
		// code...
}

async {
		// code...
}
 

Both are non-blocking functions capable of launching new coroutines in parallel. Following are the important differences between the two :

Deferred & await()

Becuase async() is a non-blocking function, the result of coroutine launched can’t be returned directly. Instead, coroutine is launched asynchronously and result’s Deferred object is returned immediately which can be used to access the result in future. To access the result from Deferred object, use Deferred#await() function.

 suspend fun Deferred<T>.await(): T
 

Example :

 val client = HttpClient(CIO)

fun main() {
		runBlocking {
				val res1: Deferred<String> = async { getMathFact(55) }
				val res2: Deferred<String> = async { getMathFact(120) }

				println("Result1 = ${res1.await()} & Result2 = ${res2.await()}")
		}
}

suspend fun getMathFact(num: Int): String {
    println("sending R#$num...")
    return client.get("http://numbersapi.com/$num/math").bodyAsText()
}
 

Note that both Coroutines have String return type (because of getMathFact() function call), so async() function returned Deferred<String>. When invoking Deferred<String>#await(), we get String result of coroutine.

⚠️ await() is a suspend function i.e. it will suspend until the coroutine execution is finished and then only proceed.

The same program can also be written using launch() function :

 val client = HttpClient(CIO)

fun main() {
		runBlocking {
				launch { 
						val res = getMathFact(55) 
						println("Result1 = $res1")
				}

				launch { 
						val res = getMathFact(120) 
						println("Result2 = $res2")
				}
		}
}

suspend fun getMathFact(num: Int): String {
    println("sending R#$num...")
    return client.get("http://numbersapi.com/$num/math").bodyAsText()
}
 

Note that here the output cannot be printed by concatenating the two results as Result1 = $res1 & Result2 = $res2 like we did using async(). Because when using launch(), both coroutines execute seperately and there is no in-built mechanism to extract the output of coroutine.

Thus, async() - await() functions are useful when working with coroutines that return some output.

awaitAll()

Similar to joinAll() function for launch(), we have awaitAll() function for async().

 suspend fun List<Deferred<T>>.awaitAll(): List<T>
 

Following is a comparison between the two :

joinAll() function awaitAll() function
Usage Used on List<Job> to wait for multiple coroutines to finish, which are launched using launch() function Used on List<Deferred<T>> to wait for multiple coroutines to finish, which are launched using async() function
Return type Unit i.e. only used for awaiting completion List<T> i.e. list of result of coroutine

Similar to joinAll(), awaitAll() is also a suspend function i.e. it will suspend until all coroutines have finished and then only resume.

Example :

Let’s send five parallel network requests using async() and await the result of all. After all results are delivered, we simply print them.

 val client = HttpClient(CIO)

fun main() {
    runBlocking {
        val deferredObjects = mutableListOf<Deferred<String>>()

        repeat(5) {
            deferredObjects.add(
                async { getMathFact(it) }
            )
        }

        val results = deferredObjects.awaitAll()

        println("\nAll requests complete, Results =\n")
        println(results.joinToString("\n"))
    }
}

suspend fun getMathFact(num: Int): String {
    println("sending R#$num...")
    return client.get("http://numbersapi.com/$num/math").bodyAsText()
}

/* Output :

sending R#0...
sending R#1...
sending R#2...
sending R#3...
sending R#4...

All requests complete, Results =

0 is the additive identity.
1 is the most common leading digit in many sets of data, a consequence of Benford's law.
2 is the only number x such that the sum of the reciprocals of the powers of x equals itself.
3 is the first number, according to Proclus, being the first number such that n2 is greater than 2n.
4 is the smallest composite number, its proper divisors being 1 and 2.
 */