Kotlin Coroutines
Published On: 2021/03/15
Concurrency is one of the main keywords used by many of the programmers nowadays.In the Java world, we could use threads to achieve concurrency which may cost you the readability of the code and sometimes performance. When Kotlin evolved as a mainstream language, they implemented the concept of coroutines to achieve concurrency using a safer and less error-prone abstraction of asynchronous operations called suspended functions.
A coroutine might be defined as a forked but coexisting route/thread to the main thread which does not block the main thread during its execution, and joins back to the main thread once the result of its execution is ready. The key concept of coroutine is suspend and resume.
A small coroutine story
Let us understand the concept of coroutine with a realtime example and move to the kotlin code. We could take the example of a conference call where there could be management and technical team members present to find out the solutions for one or more problems or to take multiple major decisions.During the call we, the technical people, used to get instructions to query some data from the database or may be to check some implementation in the code.
In this example you could see a coroutine and implementation of suspend and resume concept. Here the main thread is the conference call and the coroutine is the fork that technical person has created to complete his task which runs along with conference call. This way you could have multiple coroutines generated from the single thread which is less expensive than creating multiple threads.
A simple code example
Many programming languages provides coroutine implementation. In this tutorial, I will be using the examples of Kotlin coroutine. We could create coroutines in Kotlin using launch {} and async {} blocks.
launch:
// Start a coroutine in the global scope
launch {
delay(1000)
println("Hello")
}
The delay function here suspend the coroutine instead of blocking the thread in which the coroutine is being executed. When the thread finds that the coroutine is suspended then it goes back to the pool so that it could be used for some other task. When the coroutine is ready with the result then it resumes the execution on a free thread in the pool.
async: When we are using lauch structure to create a coroutine, we are just creating a job to execute a block of code without expecting any value in return. If we want the block of code executing in the coroutine to return a value then we should use the async structure.
The asyc structure return a Deffered< T > type which has a method await() to get the result.
val sampleRoutine = async {
...
}
// compiler complains here as the waiting is outside the coroutine scope
sampleRoutine.await();
runBlocking: This structure blocks the current thread till the coroutine completes its task. This is something like renting a car and parking it when you visit a place. No one else could use it.
runBlocking {
val sampleRoutine = async {
...
}
sampleRoutine.await(); // compiler will not complain as it is inside coroutine scope
}
coroutineScope: This structure just suspend and release the underlying thread for other usages. This is something like taking a taxi to visit a place and releasing the taxi. When you want to come back take another taxi (a thread from the pool) and continue your journey.
coroutineScope {
val sampleRoutine = async {
...
}
sampleRoutine.await(); // compiler will not complain as it is inside coroutine scope
}
Conclusion
In this tutorial, I have tried to explain the coroutine using realtime examples. Coroutines are an elegant way to achieve concurrency. Coroutines are lightweight fibers which starts the execution in one thread, gets suspended for a while , and then resumes the execution in another thread.