with open("some-file") as fo: data = fo.read(1024) while data: yield data data = fo.read(1024) def infinite_sequence(): """Saving money on RAM""" i = 0 while True: yield i i += 1
1 KB of text >>> print("Doing some other work") Doing some other work >>> next(whats_this) The next KB of text But how often do you need to do that … really?
receive? >>> whats_this = magic() >>> next(whats_this) 1 KB of text >>> print("Doing some other work") Doing some other work >>>whats_this.send("Some other data") The next KB of text and Some other data
generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. http://en.wikipedia.org/wiki/Coroutine
familiar program components such as cooperative tasks, exceptions, event loop[s], iterators, infinite lists and pipes. http://en.wikipedia.org/wiki/Coroutine
def StateMachine(): data = yield STARTED while True: should_terminate = process_data(data) if should_terminate: yield FINISHED break data = yield IN_PROCESS
while True: data = yield if not data % div: drain.send(data) @coroutine def transform(op, drain): while True: data = yield new_data = op(data) drain.send(new_data)
yield for listener in listeners: listener.send(data) drain = printer() double_and_print = transform(lambda n: n * 2, drain) filter_and_print = filter(2, drain) event_node = EventNode(double_and_print, filter_and_print) data = producer(10) for val in data: event_node.send(val)
instantiate the generator object var gen = genfun(); function next(err, answer){ var res; if (err){ // if err, throw it into the generator return gen.throw(err); }else{ // if good value, send it res = gen.next(answer); } if (!res.done){ // if we are not at the end we have an async request to fulfill // we do this by calling `value` as a function // and passing it a callback that accepts two positional arguments, `err` and `answer` // for which we'll just use `next()` res.value(next); } } // Kick off the async loop next(); }
use coroutines, it is critically important to not mix programming paradigms together There are three main uses of yield • Iteration (a producer of data) • Receiving messages (a consumer) • A trap (cooperative multitasking) Do NOT write generator functions that try to do more than one of these at once.”
Concurrency by David Beazley • Generators in V8 by Andy Wingo • Analysis of generators and other async patterns in node by Gorgi Kosev • Tortoises, Teleporting Turtles, and Iterators by Reginald Braithwaite • Programming in Lua Chapter 9 by Roberto Ierusalimschy • Wu.js by Nick Fitzgerald • Suspend.js by Jeremy Martin • A Closer Look at Generators without Promises by James Long