Ever since Kotlin introduced coroutines there has been a plethora of posts that showcased their usage in networking or multi threading scenarios. Inevitably many developers when asked what a coroutine is their first answer was “a lightweight thread” or “a way to write clean asynchronous code”. Unfortunately this is not the definition of a coroutine but rather a couple of things that a coroutine can help us with.
Routine (aka Subroutine)
So what is a coroutine? To answer that we must first understand what a routine is.
A routine is nothing more than the common function that we all use every day. Its main characteristic is that its execution must come to a completion before returning to the caller. It does not hold any state and calling it multiple times is like calling it for the first time.
On the other hand a coroutine (a concept that is way older than Kotlin) is a function that can hold its current state allowing us to pause and resume its execution at certain suspension points. This can be of great help when we need to write concurrent code, meaning, when we need to run two tasks at the same time by executing small parts of those tasks one at a time.
For example, if we have task A broken in two parts (A1, A2) and task B broken in two parts as well (B1, B2), we can write code that executes first A1, then B1, then A2 and finally B2.
Building a coroutine
Our goal is to convert the above routine into a coroutine and to do so we need to have a blueprint:
So, step #1 is to separate the states into blocks of code and to do that we are going to use the
the problem here is that the code does not compile since the states do not communicate and are missing important information.
To fix it we are moving to step #2 where the state parameter will be used as a vessel to pass data from one state to the other:
the code now has distinct states that share data but it cannot resume correctly since there is no way to move from one state to the other.
Step #3 addresses that by updating the state’s label allowing the function to resume from where it was paused:
and that’s it.
saveUserTasks is now a coroutine where every call executes a small part of the function allowing us to pause and resume the task:
We did manage to convert a routine to a coroutine but the example did not show the power of using coroutines which is concurrency. Lets change that.
To make things a little bit easier we are going to package a few common functionalities together
which allows us to create these
This way we can call the two functions as such:
As you can see the two functions are being executed concurrently. First we load the user, then we download the settings, then we load the user’s task and so on and so forth!
My goal with this post was to give you a better understanding on what a coroutine is and I did it by using the concept of a finite state machine. The same concept that Kotlin’s implementation of coroutines uses.
For digging in the actual implementation of coroutines I suggest you take a look at a couple of great posts that helped me a lot in grasping the concept: