tags : Concurrency, Programming Languages, General Programming
What?
- Implies supporting of explicit means for transferring control to another coroutine.
- Coroutine is a chunk of code than can voluntarily suspend itself. i.e yield
- Coroutines are functions whose execution you can pause
Transfer of control
Here, Coroutines have more control compared to exceptions.
Exceptions < Coroutines < Continuations
- Exceptions: A subclass of coroutines. You can implement an exception mechanism with coroutines.
- Coroutines: Can tell the code to jump back and start running exactly where it left off.
- Continuations: More details
What happens when we yield?
When we yield
, from the coroutine’s point of view
- Things that happens while it is suspended is happening inside its call to yield.
- When we resume the coroutine, this call to yield finally returns and the coroutine continues its execution until the next yield or until its end.
Uses
- Used in RAF
- I/O and concurrency, see cooperative multithreading.
- What not
Relationship with State Machines
Co-routines are to state machines what recursion is to stacks
Co-routines as an alternative to state machines - Eli Bendersky’s website
Taxonomy
See Programming in Lua : 9.1 (2003)
Note: Avoid using the word “semi-coroutine”
Based on control flow
Symmetric coroutines
- Only one function to transfer control
Asymmetric coroutines
- A function to
suspend
the execution of a coroutine - A different function to
resume
asuspended
coroutine.
Based on when the coroutine can suspend itself
Can suspend itself anywhere
- Eg. Lua coroutines
Can only suspend itself in the main body
- If there’s no pending calls in its control stack
- Basically each transfer is
yield
followed by aresume
(in lua terms) - Eg. Python generators. Python generators must be written as generators, and cannot easily be factored into smaller functions. In other words,
yield
is syntactic, and can only be in the lexical body of the generator function. - How the heck does async/await work in Python 3.5?
Blocking and Non-blocking
Blocking
- Blocking is about blocking the main thread
How to convert from blocking to non-blocking?
- Non-blocking IO depend on “readability/writability”
- For different IO there are different things that determine it.
- In case of files, reading files will always block the main thread. Only solution I know of is to use thread pools, there should be other better options tho ig.
Non-blocking
- asynchronous - Refactor blocking I/O in Lua using coroutines - Stack Overflow
- Non-blocking is about not blocking the main thread
- So if you write a non-blocking method “fetch” that gets data from across the world, it’ll take that time but and make “the caller function” wait, but the main thread will be free to do go on with other stuff.
Implementing non-blocking I/O
- polling (poll/select etc.)
- event loop/event handling framework of some sort
Async/Await
- Async/Await is slightly different than coroutines.
async/await
is a syntax, whereas coroutine itself is a broader idea. Eg. Many languages useasync/await
to implement coroutines but not exactly. - Allows asynchronous, non-blocking code can be written, with minimal overhead, and looking almost like traditional synchronous, blocking code.
- async/await only will switch context at a yield point