To begin, I want to introduce you to two important multitasking/ concurrency terms.
- Pre-emptive Multitasking
- Non-preemptive/ Cooperative Multitasking
Operating systems manage and execute multiple threads via a technique called Pre-emptive multitasking.
This is when the OS allocates an execution time slice to each thread and once this time is over, it interrupts the running thread and switches to execute another(using a Scheduler), repeatedly (a process called Context Switching).
Multitasking with multiple threads using this technique comes with its own challenges.
One of the major ones is the need to save the context (current state) of the running thread and restore it in the next execution cycle. This context switch consumes CPU cycles and memory, introducing overhead.
This is when logical threads (that do not relate to OS-level threads in a one-to-one fashion) are created at the user/ application level.
Each thread is responsible for managing its own execution and deciding when to give up CPU time to allow other threads to run.
This approach significantly reduces overhead on the CPU.
Cooperative multi-tasking can be implemented using Co-routines.
Next, let’s learn about them.
What Are Co-routines?
Co-routines are programming constructs that allow a thread to be paused and resumed as per the developer’s needs (instead of the OS doing this using Pre-emptive Multitasking).
They are particularly useful when we encounter blocking scenarios like reading from or writing to files, making network requests, and interacting with databases.
By using coroutines, we can start a blocking operation, pause the coroutine while waiting for the result, and then resume the coroutine when the result is available, all without blocking the main thread.