By Noel Niles
A generator function in Python is created using a yield
expression.
When a generator function is called it returns an iterator called a
generator. When one of the generator's methods is called the execution
proceeds to the next yield
statement. When execution reaches a yield
statement execution is suspended and the expression list is returned to
the generator's caller.
The following data is retained until another call to one of the generators methods.
- local variables
- the instrucion pointer
- the eval stack
- exception handling state.
Python generators have a lot in common with coroutines.
- They yield multiple times
- They have more than one entry point
- They can be suspended
The only difference between a coroutine and a Python generator is that a generator always returns control to it's caller, but a coroutine can decide resume execution in a different function.
The execution time is simulated with a call to time.sleep()
. Although
arbitrary I tried to make the sleep times coorispond to operations. In
other words a function should perform and operation and then sleep in
order to pretend it's working hard and to give us something to watch.
It's easy! There are two demonstrations. Each demonstration performs three functions on a lists of integers.
- First two lists are added together; in other words the elements from one list are added to the end of another list.
- Next each element in the list is raised to a power (the details aren't really important).
- Finally the list is sorted and the results are returned.
Each function blocks so the execution time is the product of all three operations.
$ python -m gent slow
Each function yields the result as soon as it's computed.
$ python -m gent fast
- Fix the sort function in fast_chain.py so that it doesn't block but also returns the correct sorted value.
- Add another function to the slow_chain and fast_chain. Both versions should consume a noticeable amount of time, but the fast_chain version should be able to yield values immediately.
- Make a coroutine that receives values and yields results.
- Implement a thread pool Task that offloads the generators to multiple threads.
###References
- Task and Coroutines
- Syntax for Delegating to a Subgenerator
- A Curious Course on Corotutines and Concurrency
- Generator Tricks for Systems Programmers
Copyright 2015 Noel Niles