Two ways to pause
A coroutine must remember where to resume. The two main designs differ in where that memory lives.
Stackful coroutines
A stackful coroutine owns a full separate call stack. When it pauses, the runtime simply switches stack pointers, so the whole chain of nested calls is preserved.
- It can yield from any depth, even deep inside helper functions.
- It costs real memory because each coroutine reserves a stack.
Stackless coroutines
A stackless coroutine has no separate stack. The compiler transforms the function into a state machine, storing only the variables that must survive a pause.
- It is very memory light, so millions can run at once.
- It can usually yield only from the coroutine body itself, not from arbitrary nested calls, unless those calls are also coroutines.
Choosing between them
Stackful designs feel like ordinary threads and suit complex call chains. Stackless designs scale to huge counts and dominate modern async languages, at the cost of more compiler machinery.
Key idea
Stackful coroutines keep a whole call stack so they yield from any depth but use more memory, while stackless coroutines store just the needed fields as a state machine to scale to millions.