Thread dealers: Kotlin Coroutines for beginners !

Enes Zor
6 min readMay 2, 2021

Once multi-threaded programming is the norm, coroutines are became clear again nowadays. With reactive programming and architectural changes, developers needs to manage thread mostly. So, kotlin coroutines are started to use because it is really compatible any other components especially on Android era. You can indicate threads or thread pool which coroutines can work on.

After my overview, I’d like to present my main purpose to write this article. My main purpose is that explain what is the coroutines and how they work with each other in just entry level. To do that, I will try to explain :

  • Coroutine scopes and builders
  • suspend functions
  • Dispatchers

Why I feel to explain coroutine scopes and builders in just explanation is that I do not want to you confuse in further code snippet parts. After these topics explanation is done, I will try to explain real magic with interaction of these three topics. Fasten your belts! We are rising up !:)

The Scope

All coroutines are managed by CoroutineScope. The primary responsibility of CoroutineScope is cleaning and cancelling when the coroutines are no longer needed. GlobalScope implements CoroutineScope. It can be called global version of CoroutineScope. Its lifetime is really long. It can be alive throughout all application progress. It does not make any sense when you are doing IO operation especially in Android Development. When your IO progress is end up, you probably want to clean your coroutines session so viewModelScope can fit your purpose in this point.

The Builder

In this part, I will try to explain builders with just explanation. Moreover, I’d like to notice that this builders are deep matters alone.

Coroutine builders build and start new coroutine. They perform what we indicates their functions which take lambda expressions. Let’s have a look into types of builders.

  • launch() = It starts new coroutine without blocking the current thread. It can be called “fire and forget” coroutine builder. If you want to execute a code block without expect any return value, you can use this builder. By the way, launch () returns Job object.
  • async()= This coroutine builder returns a Deferred object. It is sub-type of Job. async() receives lambda type and deliver this lambda object to callers via Deferred type. If you call await() method on Deferred object , it blocks until lambda expression result is ready.
  • runBlocking()= Imagine that you can call suspend function from everywhere. It is possible with runBlocking(). Sometimes, you are not in position to set up your coroutine. And, you need to execute suspend function immediately with other methods. In this point, you can generate this purpose with runBlocking(). It will execute its lambda expression as a coroutine. And, it will never return until block completes itself. We can name this builder as easy coroutine play area.

The suspend function

suspend keyword means that the current coroutine can suspend current code body which it has.(In current dispatcher) And, feel free to run another code from another coroutine builder.

suspend methods are needs to be called from Coroutine builders or another suspend method inside.

I would like to explain suspend function magic with some code snippets.

OUTPUT

This is executed immediatelyFirst point in first coroutineFirst point in second coroutineSecond point in first coroutineSecond point in second coroutine

As you see we enqueue two coroutine in main function. When main function is executed, first coroutine is executed. And in case of suspend function hit, Kotlin suspend this coroutine and execute second coroutine. This process continues in second coroutine. When it hit suspend function , Kotlin continue first coroutine executing while removing its suspend. And, finally two coroutines are completed. In single coroutine , everything is sequential. You can see that it is possible to work with multiple coroutine concurrently. As a result, you can switch coroutines with Kotlin coroutines. suspend function always completes his work (code body) before switch coroutine.

suspend function usage is very cheap in coroutine environment. But we should not run long running task in suspend function. Think that it is very small and particular piece of coroutine. The code which we run inside suspend function , should take milliseconds times to make compiler happy. If we want to use long running task in coroutine with same purpose , we should execute our code body inside withContext instead. It presents Dispatcher opportunity as well. Moreover, it is known that global type of suspend function.

Dispatchers

Dispatchers are tied to thread pools. Moreover, they know that how to coroutines are arranged and run. They deal with thread pools in coroutine environment. We will have look three popular dispatchers in detail.

  • Dispatchers.Default

If we do not define any dispatchers while build new coroutine in launch and async builder , this dispatcher is used by default. This dispatcher is for generic background work.

  • Dispatchers.IO

This dispatcher is design for generic background work related blocking , network and disk IO process. This dispatcher doesn’t have special thread pool. It use same thread pool with Dispatcher.Default. It is tend to blocking unlike Dispatcher.Default.

  • Dispatchers.Main

This dispatcher is design for UI work. Moreover, it is known as “magic” thread as well. If you wanna update your UI , you should use this thread in android era.

If we have conclusion, each coroutine has default dispatcher. But we should know which thread we have to use in special cases.

Coroutine is not equal thread

A coroutine is tied to dispatchers. Dispatchers are tied to thread pools. So , a coroutine is tied to thread pools. When we create coroutines , give the dispatcher. Thats all! Rest of all thread switch process is handled by Kotlin. Let’s we check them out over the diagrams step by step.

STEP 1:

Figure 1

You see that we have coroutines and thread pool in dispatcher. It can be any type of dispatcher. It contains suspended coroutines which has them instantly and thread pool which meet them into any time. This is our situation before any coroutine entrance in this dispatcher.

STEP 2 :

Figure 2

In this step , our new coroutine is arrived in dispatcher unlike step 1. We assume that our coroutine is ready to run immediately and dispatcher execute our coroutine. As you see, dispatcher elect one thread from thread pool and executed it into there. It can choose any of them but its choice was thread 1. By the way, another coroutines are still suspend situation.

STEP 3:

Figure 3

In this step, dispatcher does not have coroutine which has executed instantly. Instead of it, our coroutines pool is more than previous. The reason that our coroutines in coroutines pool, it hits a suspend point. Yes, it hit a suspend point and goes into the bucket of other suspended point. We already know suspend keyword functionality from previous parts. You can get rid of abstraction. I try to demonstrate in here.

STEP 4:

Figure 4

In our final step, actually is not final step for coroutine. It is just last in our review. After this step completed. We can see our first step if the our same case is generated by compiler. As you see that, our coroutine suspension was removed in here. It gets unblocked. But in this case, dispatchers continue to execute it in another different thread from the thread pool. That’s why I say that we do not care about how to threads are switched. Dispatcher are handled them instead of us.

To sum up, we tried to explain coroutines and their working mechanism with milestones in entry level. I am planning to come more details in further articles. Feel free to make any comment and suggestion. Thank you for your read :)

--

--