What is suspension in coroutines and how it works?
What is "Suspending" in Coroutines?
A coroutine is a lightweight thread-like structure that allows you to write asynchronous code in a sequential manner. The key feature of a coroutine is its ability to suspend its execution without blocking the underlying thread. When a coroutine suspends, it pauses its execution at a certain point and allows the thread it is running on to do other work. Later, the coroutine can resume from where it left off.
How Does a Coroutine Suspend a Task?
When a coroutine suspends, it does a few things:
State Capture: The current state of the coroutine (like the current instruction pointer, local variables, etc.) is captured. This allows the coroutine to resume later from exactly where it left off.
Thread Release: The coroutine tells the thread to go ahead and do something else. The thread is free to execute other coroutines, handle other tasks, or even be released back to the thread pool.
Control Return: Control is returned to the caller or the event loop that manages the coroutine’s execution. The coroutine is now in a suspended state.
Resumption: When the condition for the coroutine to continue (e.g., data is available, or a timer has expired) is met, the coroutine resumes. It picks up from the state that was captured during suspension.
Why Can't a Thread Do the Same?
A thread is a more heavyweight construct. Unlike coroutines, threads don’t inherently support suspending and resuming tasks without blocking:
Blocking vs. Non-blocking: If a thread waits for something (like I/O or a sleep operation), it blocks. This means the thread is doing nothing, just waiting, and it cannot be used for other tasks until the wait is over. This blocking is inefficient in many cases, especially when dealing with a large number of tasks.
Context Switching: Threads rely on the operating system to manage their execution, which includes suspending and resuming them. This involves context switching, where the CPU saves the state of the thread, switches to another thread, and later restores the saved state to resume the original thread. Context switching is more expensive compared to the suspension of coroutines, both in terms of time and memory.
Resource Usage: Threads are more resource-intensive because they require a larger memory footprint (e.g., stack space) and incur more overhead in context switching compared to coroutines.
Where is the Task When Suspended in a Coroutine?
When a coroutine is suspended:
The task is effectively "paused" and its state is saved.
The actual work it was doing is not being processed; it's waiting.
The thread that was running the coroutine is free to execute other coroutines or tasks.
This makes coroutines particularly well-suited for tasks like network requests, where you often need to wait for a response without doing any work in the meantime.
Summary
Coroutines suspend by capturing their state and yielding control, allowing the thread to continue with other tasks.
Threads block when they wait, which means they can’t be used for other tasks during that time.
Coroutines are more efficient for handling many asynchronous tasks because they allow for non-blocking, lightweight suspensions and resumptions.

