Skip to main content

Kotlin Coroutines : A Comprehensive Introduction

Photo by Fleur Treurniet on Unsplash
“Redesigning your application to run multithreaded on a multicore machine is a little like learning to swim by jumping into the deep end.”
—Herb Sutter, chair of the ISO C++ standards committee, Microsoft®

In this article

  • What are coroutines?
  • Blocking vs. Non-Blocking
  • Kotlin Coroutines
  • Suspending functions
  • CoroutineScope
  • Coroutine builders
  • Coroutine dispatcher
  • Coroutine start
  • Conclusion

What are coroutines?

Coroutines have been around for quite a time now. They are in-fact one of the ideas which helped develop multitasking operating systems. A coroutine in trivial most is a subroutine or function generalisation which in non-preemptive environment (operating system or OS in short) can voluntarily yield the CPU time so that other such sub-routines can use it for themselves without losing the results of previous computations and then can continue from wherever it left. Hence coroutine basically are sub-routines which sacrifice their CPU time so that system as whole can win—Go coroutines Go.

Multitasking operating systems are type of operating systems in which multiple number of tasks can be performed concurrently (not parallelly) with the help of context switching.
Non-Preemptive OS environments are multitasking OS environments in which process yields the control (CPU time) voluntarily so that other applications can run concurrently.

Blocking Vs. Non-blocking calls

A blocking call in process or program is an instruction or list of instructions which intentionally or unintentionally blocks the thread from processing further unless and until this call completes. On the other hand if this same call has been otherwise dispatched to another thread for execution so that the main thread keep on executing asynchronously then call would have been non-blocking. In non-blocking calls the parent thread is notified with results with the help of callback.

Kotlin Coroutine

Coroutine in kotlin are implemented as short lived lightweight threads (not the threads that Thread object represents). They are dispatched with the help of a ThreadDispatcher or WorkerDispatcher and their liveness depends upon the scope in which they were created and then launched.

Lot's of languages have language level support for coroutines but what differentiates kotlin's approach from them is that koltin (according to me) provides a good interface to manage and control them. Also because kotlin is functional at heart it's more verbose and easier to write coroutine in it. Let's see a simple example

In the second line we import definition of coroutine and relevant methods into the program. Then we create and launch coroutine at line 5 with launch coroutine builder under the GlobalScope. Inside coroutine we called non-blocking suspending function delay with amount of time in milliseconds we want to delay the coroutine and at last we print “World”. Note that call to this coroutine doesn't blocks the main thread. Lastly we made a blocking call to sleep method on the main thread so that we can outlive the coroutine and receive the results back.

There are lot's of words not making sense, right?. Let's go through them.

What is Suspending function?

A suspending function as its name specifies is a function which we expect will take time to complete its execution. And hence will potentially block the thread which we don't want to do to the main thread. Kotlin has keyword suspend which indicates to the compiler that function followed by it(suspend) is a suspending function and must be executed inside a coroutine. For example delay.

Suspending functions can also be stopped in between and started again from where their execution was stopped without loosing the context as well as previously computed results.

At line 2 we indicated that this method is suspending by marking it with suspend. A suspending function can call both suspending and non-suspending functions inside it's block hence call to delay doesn't bother compiler. At line 8 (comment), if you uncomment this line then you will get an error from compiler i.e “A suspending function cannot be called from non-suspending context”. Lines from 9 through 12 we launched a new coroutine with launch coroutine builder which returns a job class instance with which you can query for various things about coroutine viz. isCompleted, isCancelled and isActive. Lastly we went inside infinite while loop which keeps on pooling the job asking for its completion until it's done. If we didn't have done it then main method would had died even before coroutine would have completed.

What is Coroutine Scope?

A coroutine scope such as GlobalScope, trivially is lifetime throughout which a coroutine lives or is running. Every scope consists of coroutineContext which keep track of execution of coroutine. Every coroutine builder is an extension on CoroutineScope and hence inherits the context that come with the scope so that it could propagate both context elements and cancellation to coroutines build with it.

Coroutine builder is functional extension over coroutineScope used for building and launching coroutines.

Some common coroutine builder

launch
launch is fire and forget coroutine means you don't care about results; all you want to achieve is that the instructions wrapped around by launch run without blocking the main thread for example saving an image or file. However when exception happens during execution of launch, it is propagated throughout to parent potentially crashing the application.
async
async is executing the task asynchronously and then processing the result when it is available. It returns Deferred object's instance which is a Future with results. For example network calls.
runBlocking
runBlocking is for testing regular coroutine code hence it should not be used when not required. It potentially block the thread and waits for all other coroutines to complete i.e join.

What is coroutine Dispatcher?

Coroutine dispatcher is an instance of singleton abstract class CoroutineDispatcher which inherits the ContinuationInterceptor. ContinuationInterceptor is a class which keeps track of resuming coroutine after suspension cycle. It intercept the continuation and dispatches the coroutine onto thread pool. Following is list of dispatchers provided by kotlin-coroutine api.

Dispatchers.Default
The default CoroutineDispatcher that is used by all standard builders like launch, async, etc. It is backed by a shared pool of threads on JVM. The level of priority that these threads have is equal to amount of cores that CPU has.
Dispatchers.IO
This dispatcher is specifically designed for dispatching blocking IO tasks to a shared pool of threads. Additional threads in this pool are created and are shutdown on demand. The number of threads used by this dispatcher is limited by the value of “kotlinx.coroutines.io.parallelism”.
Dispatchers.Unconfined
Coroutines dispatched with unconfined dispatcher are not confined to any thread or pool of threads and hence they are executed in the same call-frame(thread) until the first suspension. Note that it is still experimental.

CoroutineStart

Last but not the least piece of puzzle is CoroutineStart, CoroutineStart defines the start option for coroutine in CoroutineBuilder(see signature of launch).

CoroutineStart.DEFAULT
It immediately schedules coroutine for execution according to its context. Normally execution case with launch and async.
CoroutineStart.LAZY
Coroutine starts lazily, only when it is needed. This can come in handy in cases where you first want to wait for something or some event to occur before starting executing the coroutine.
CoroutineStart.ATOMIC
Atomically (in a non-cancellable way) schedules coroutine for execution according to its context. That is it must execute unless some internal exception occurs.
CoroutineStart.UNDISPATCHED
It immediately executes coroutine until its first suspension point in the current thread. However, when coroutine is resumed from suspension it is dispatched according to the CoroutineDispatcher in its context.

Conclusion

Well, That's all folk. I hope that article helped you in understanding the coroutines and kotlin's implementation of them. If you have any question you can ask them in comment section. I know this article is more of theoretical one no worries in next one we'll implement few real world examples with coroutines in Android development. Comment if you liked it; Follow if you loved it(show some love naa ❣). Have a nice time.

Comments

Popular posts from this blog

Programmer? A Computer Programmer?

“Programming is like sex. One mistake and you have to support it for the rest of your life.” —Michael Sinz Well, to start with, “A programmer is someone who writes computer code, which tells computer what to do? and how to do it?” . Computing machines are dumb, trust me they are. They have enormous processing power but they don’t have hardware to direct this power to any productive use. And thats exactly where programmer kicks in. Programmers however are not the wizard depicted in the movies. They are humans like me and you. Its just that they think much more rationally than average human does. Types of programmers: The System Programmers: First of all a great tribute to these guys. They are the one who deal with software at the lowest level. They have veteran low level languages (languages which closely resemble with the hardware) —Assembly Language, Machine language in their arsenal. A typical system programmer works closely with hardware engineers bec

Kotlin : An introduction

Photo by wu yi “A language that doesn't affect the way you think about programming is not worth knowing.” ―Alan J. Perlis World was nice and there was only assembly(“real programmers code in assembly”) but then one day out of blue he (hey! don't look at me like that I too don't know his name) came and said let there be compilers and interpreters(line by line) that will translate languages easy to read(uh! nah not really) and write into assembly to make programming fun again and that gave birth to an era of exotic new programming languages called procedural programming languages. Procedural programming languages were doing fine but after some time lot's of programmer started loosing their objects because of stateless functions which globally caused chaos. Seeing all this made him angry. So he said, “Procedural languages, I command you to treat everything as an ‘Object’ which will have it's own properties(attributes) and behavior(methods)”. They respond