Python生成器是一个很棒的功能。它允许我编码复杂的,可能是递归的遍历逻辑,并将其与用户分离。通常我会像下面的代码一样使用它
TREE = {
1: [2,3],
2: [],
3: [4,5],
4: [6],
5: [],
6: []
}
def query_children(node):
return TREE[node]
def walk_tree(root):
# recursive tree traversal logic
yield root
children = query_children(root)
for child in children:
for node in walk_tree(child):
yield node
def do_something():
# nice linear iterator
for node in walk_tree(root):
print(node)
Tornado使用生成器是实现协同程序,这也是构建异步函数而不回调的好方法。
然而,当我试图同时使用它们时我会感到困惑。
@gen.coroutine
def query_children(node):
...
raise gen.Return(children)
def walk_tree(root):
# recursive tree traversal logic
yield root
children = yield query_children(root)
for child in children:
for node in walk_tree(child):
yield node
def do_something():
# nice linear iterator
for node in walk_tree(root):
print(node)
在新的walk_tree中,第一个yield是常规的Python yield。第二个产量是龙卷风。他们可以一起工作吗?
答案 0 :(得分:3)
Python生成器协议基于同步接口;不可能像协程一样使用异步代码作为与for
一起使用的生成器的一部分(协同程序最重要的规则:调用协程的任何东西也必须是coroutine,或者至少知道coroutines。for
语句对它们一无所知,它就是调用你的生成器的东西。相反,我建议使用tornado.queues.Queue
:
@gen.coroutine
def query_children(node):
...
raise gen.Return(children)
def walk_tree(queue, root):
# recursive tree traversal logic
yield root
children = yield query_children(root)
for child in children:
for node in walk_tree(child):
yield queue.put(node)
yield queue.put(None)
def do_something():
queue = tornado.queues.Queue()
IOLoop.current().spawn_callback(walk_tree, queue, root)
while True:
node = yield queue.get()
if node is None:
break
print(node)
答案 1 :(得分:0)
我得到了这个工作。我不是在非协程walk_tree()
中使用yield,而是通过调用IOLoop.run_sync
来获取子节点来同步运行它。我是龙卷风新手。所以,如果这是一个合法的解决方案或者还有其他更好的方法,请评论。
TREE = {
1: [2,3],
2: [],
3: [4,5],
4: [6],
5: [],
6: []
}
@gen.coroutine
def query_children_async(node):
raise gen.Return(TREE[node])
# this is a regular Python generator
def walk_tree(root):
# recursive tree traversal logic
yield root
# call .result() of the Future
children = IOLoop.instance().run_sync(lambda: query_children_async(root))
for child in children:
for node in walk_tree(child):
yield node
@gen.coroutine
def do_something(root):
# just collect the result
result = [node for node in walk_tree(root)]
raise gen.Return(result)
修改1.使用
.result()
的原始提案不起作用。我有 " DummyFuture不支持阻止结果"当我有一个 非平凡的query_children_async()
。