Coroutines - Launch & async

Coroutines - Launch & async

In this Kotlin Coroutines series , we have learned about the following

What is Coroutines ?

  • is used to do suspendable computation
  • is a light weight thread
  • runs a block of code concurrently with rest of code

Coroutines Scopes

  • which decides the lifespan of Coroutines

Coroutines Context

  • Coroutines always execute in some context represented by a value of the CoroutineContext type

Dispatchers

  • Dispatchers which is a reserved thread for specific action to take place.

Suapend Fuctions

  • can be started , paused and resumed
  • it can be called from another suspend functions or a coroutine

Now we need to start the coroutines which can done by the one of the following

  • Launch
  • Async

Launch

  • is a coroutine builder
  • launches a new coroutine concurrently with the rest of the code, which continues to work independently

Code

Log.d("Coroutines", "Main : ${Thread.currentThread().name}")
lifecycleScope.launch (Dispatchers.IO){
  Log.d("Coroutines", "lifecycleScope : start of launch")
  Log.d("Coroutines", "lifecycleScope : ${Thread.currentThread().name}")
  delay(3000)
  Log.d("Coroutines", "lifecycleScope : end of launch")
}
Log.d("Coroutines", "Main : continues the execution")

Output

18:40:28.374 D/Coroutines: Main : main
18:40:28.404 D/Coroutines: Main : continues the execution
18:40:28.406 D/Coroutines: lifecycleScope : start of launch
18:40:28.406 D/Coroutines: lifecycleScope : DefaultDispatcher-worker-1
18:40:31.411 D/Coroutines: lifecycleScope : end of launch

As you can see in the above code

  • the coroutine inside launch block is executing concurrently with the rest of code
  • end of launch is printed after the delay
  • continues the execution is printed even before the start of launch block which indicates the concurrency in the code

launch can be used in a scenario where we don't need the result from the coroutines and it can be used in fire and forget scenarios

Async

  • used to start a corooutine
  • it blocks the underlying thread at await function's entry point .

Code

There are two suspend functions to do two different dummy network calls

private suspend fun doNetworkCallOne(): String {
  Log.d("Coroutines", "doNetworkCallOne : ${Thread.currentThread().name}")
  delay(1000)
  return "Network One Result"
}

private suspend fun doNetworkCallTwo(): String {
  Log.d("Coroutines", "doNetworkCallTwo : ${Thread.currentThread().name}")
  delay(3000)
  return "Network Two Result"
}

Now lets call the above two dummy network functions from async and wait for its result fromawait

Log.d("Coroutines", "lifecycleScope : start of async")
val resultNetworkCallOne = lifecycleScope.async(Dispatchers.IO) {
  doNetworkCallOne()
}
val resultNetworkCallTwo = lifecycleScope.async(Dispatchers.IO) {
  doNetworkCallTwo()
}
Log.d("Coroutines", "lifecycleScope : ${resultNetworkCallOne.await()}")
Log.d("Coroutines", "lifecycleScope : ${resultNetworkCallTwo.await()}")
Log.d("Coroutines", "lifecycleScope : end of async")

Lets check the Output

19:19:28.600 D/Coroutines: Main : main
19:19:28.623 D/Coroutines: lifecycleScope : start of async
19:19:28.633 D/Coroutines: doNetworkCallOne : DefaultDispatcher-worker-1
19:19:28.634 D/Coroutines: doNetworkCallTwo : DefaultDispatcher-worker-3
19:19:29.641 D/Coroutines: lifecycleScope : Network One Result
19:19:31.640 D/Coroutines: lifecycleScope : Network Two Result
19:19:31.640 D/Coroutines: lifecycleScope : end of async

In the above code ,

  • doNetworkCallOne() and doNetworkCallTwo() is called from async and from the output , we can see thread info inside each function is printed .
  • once await() is called on both functions , functions blocked its respective thread until the result is returned
  • As end of async is executed after obtaining the result from both the await function

Please leave your comments to improve.

Happy coding