我怎么知道所有期货都在龙卷风中得到解决?

时间:2014-07-01 14:07:10

标签: python tornado future

我有一些解析应用程序,它基本上执行以下操作

  • start()方法添加到IOLoop作为回调以在下一次迭代时调用
  • start()调用另一个函数,我们称之为get_input()
  • get_input()是一个协同程序,它通过网络获取一些数据,然后通过在第一步中添加process_input()添加它来安排另一个协程start()
  • get_input()还检查某些条件,这取决于获取的数据,并可以使用调整后的参数进行自我调度

现在,在这个条件呈现False后,我知道不会有任何新的输入项需要处理。
但我怎么知道还没有get_input()process_input()的期货尚未解决?

我想这可以通过实现一种计数器来解决,计数器在每次调用process_input()时递增,在解决后递减。 但是,如果有一系列不同的协程?我如何跟踪他们的状态,这样如果我停止IOLoop,在解决之前没有任务会死掉?

也许,应该有某种分层计数...

编辑:

2 @dano 好的,我现在看到......我很不专心。你真的不会阻止,因为它自己的呼叫在这个列表中 但是!

  1. 此类组织要求必须使用yield构造,否则add_callback否则我们将失去“等待”概念
  2. 递归级别增长..嗯,dunno,如果它太糟糕了
  3. 我今天想出的是“未来” 我创建了一个裸Future()对象。
    我用我的装饰器装饰每个@coroutine启用的方法,它在“metafuture”中增加计数器字段,并为它们的未来添加一个自定义完成的回调,这应该减少它。

    当它达到零时,“metafuture”通过调用set_result(None)来解决 这也是一个IOLoop回调,恰好产生了这个元素:

        @coroutine
        def wait_for_complete(self):
          yield self._input_data_collected
          yield self._all_futures_resolved
          self.complete()
    

    所以在那之后我们知道没有未来的未来。这是一种比手动实现引用计数更难的方法,但它也涵盖IOLoop.add_callback()添加任务的方式

1 个答案:

答案 0 :(得分:4)

您可以编写方法,以便在完成所有工作之前不返回,而不是安排回调。然后你可以调用IOLoop.run_sync(start),直到所有处理完成后才会返回调用:

from tornado import gen
from tornado.ioloop import IOLoop

@gen.coroutine
def start():
    yield get_input()

@gen.coroutine
def get_input(*args, **kwargs):
    data = yield fetch_data_over_net()
    futs = []  # list of Future objects
    futs.append(process_input(data))
    if should_call_myself(data):
        futs.append(get_input(newargs, newkwargs))
    yield futs # This will wait for all Future objects in the list to complete.

@gen.coroutine
def process_input(data):
    # do stuff

if __name__ == "__main__":
    IOLoop.instance().run_sync(start)

我们利用协程返回Futures的事实,并且Tornado支持waiting for multiple Futures in parallel,以便我们可以同时运行,而不会实际从get_input返回(和因此start)在完成所有相关工作之前。