-
-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generators vs Callbacks #33
Comments
I have added a example https://github.com/Fonsan/curvature/blob/3c0f62d03d0e60d89ec7e0b2b290ec654ab9416b/processing_chains/callback_chain_example.py The next step is to express a tree with multiple branches that is supported by callbacks with a minimal memory footprint but would unusable in the current state with the iterator chain because of memory usage |
Here is a working example of a Fanout solution class CallbackedProcessor(object):
def __init__(self, processor, callback):
self.processor = processor
self.callback = callback
def input(self, arg):
# Since processors do not have a process_item interface we are mocking it for now
for output in self.processor.process([arg]):
self.callback(output)
class IDOutputPrinter(object):
def __init__(self, id):
self.id = id
def process(self, iterable):
for collection in iterable:
for way in collection:
print self.id, way['id']
return []
class FanOut(object):
"""docstring for FanOut"""
def __init__(self):
super(FanOut, self).__init__()
self.callbacks = []
def callback(self, arg):
for cb in self.callbacks:
cb(arg)
def link_callbacks(chain, callback = lambda collection: collection):
for processor in reversed(chain):
callback = CallbackedProcessor(processor, callback).input
return callback
normal_roads = FilterOutWaysWithTag('service', ['driveway', 'parking_aisle', 'drive-through', 'parking', 'bus', 'emergency_access'])
soft_roads = FilterOnlyWaysWithTag('surface', ['unpaved','dirt','gravel','fine_gravel','sand','grass','ground','pebblestone','mud','clay','dirt/sand','soil'])
non_soft_roads = FilterOutWaysWithTag('surface', ['unpaved','dirt','gravel','fine_gravel','sand','grass','ground','pebblestone','mud','clay','dirt/sand','soil'])
chain = [
AddSegments(),
AddSegmentLengthAndRadius(),
AddSegmentCurvature(),
FilterSegmentDeflections(),
SplitCollectionsOnStraightSegments(2414),
AddWayLength(),
AddWayCurvature(),
FilterCollectionsByCurvature(min=300),
]
f1 = FanOut()
start_callback = link_callbacks([normal_roads], f1.callback)
soft_chain = [
soft_roads,
] + chain + [
IDOutputPrinter('soft')
]
non_soft_chain = [
non_soft_roads,
] + chain + [
IDOutputPrinter('non_soft')
]
f1.callbacks.append(link_callbacks(soft_chain))
f1.callbacks.append(link_callbacks(non_soft_chain))
for collection in msgpack.Unpacker(sys.stdin, use_list=True):
start_callback(collection) |
As I realised here #34 (comment) without a proper abort signal convention by explicitly returning some value like |
I did mention before in #13 (comment)
and #13 (comment) that utilising pythons generators and the
itertools
module had some drawbacks with its "pull" design. Essentially when fanning out when usingitertools.tee
their is now flow control and one stream will get ahead of the other causingitertools.tee
to keep the not yielded objects in memory. However if one does not fan out the code comes together rather nicely.The alternative is using callbacks like the OSMParser does
OSMParser.parse(ways_callback=self.ways_callback)
. Callbacks are more flexible by allowing messages to be passed back as return values which could prove useful. Using callbacks differs from generators since they have a "push" design, you need to setup you full chain before calling parse. It is still possible to express the same chains using a callback approach.I will experiment constructing a nice callback chain
The text was updated successfully, but these errors were encountered: