2. Different approaches to multitasking
All the most widely used languages provide one way or another to create new threads and handle parallel execution of multiple tasks. So, you might ask, what is the fuss with Kotlin’s coroutines? What could the language offer more than the seamless parallel execution of multithreading?
Concurrent execution and its share of problems
Well, first of all, if you have already experimented with concurrent execution (“concurrent” meaning here that multiple execution threads are running in parallel and are able to access the same “resources” at the same time, even if that resource is as simple as a global variable), you probably know what a pain it can be. Precisely because the threads are executing at the same time, you have to be very careful to make sure that another function in another thread will not interfere with what you are trying to do in the current thread. It is not easy to walk when the floor can move under your feet any second. This can lead to a wide range of problems, which are more or less solved by an even wider range or partial and complicated workarounds. If you know about volatile, synchronized, mutexes, thread-safe, reentrant, and so on, you know what I’m talking about, and you might have nightmares about them.
Single-thread is not great either
Another solution is to give up concurrent programming entirely and handle some pseudo-parallelism by hand between your logic tasks, for example with some kind of finite-state machine. That way, you know you won’t have concurrency problems because there is never another function running at the same time as the current one. For some applications it can be the best approach, and it is especially well suited for instance for microcontrollers. However, for a large program, it quickly falls apart and usually leads to a messy and inefficient code that is hard to maintain and doesn’t take advantage of modern multicore CPUs.
An interesting alternative
Coroutines are kind of an intermediate solution between these two approaches, with some interesting twists. They provide a way to write asynchronous code (meaning here that it is not always executed in the order you write it) that is either single or multi-threaded, while simplifying concurrency problems, and making the code shorter and clearer (in some cases, a lot clearer). However, coroutines are not a magic spell that suddenly solve all the issues of concurrent programming for free, and it is therefore important to understand what they do and how they do it in order to use them properly.