Python 我怎么知道所有的未来都在龙卷风中解决?

Python 我怎么知道所有的未来都在龙卷风中解决?,python,tornado,future,Python,Tornado,Future,我有一些解析应用程序,它基本上执行以下操作 将start() start()调用另一个函数,让我们调用它get\u input() get\u input()是一个协同程序,它通过网络获取一些数据,然后调度另一个协同程序,process\u input(),将其添加为第一步添加的start() get\u input()还检查某些条件,这些条件取决于所获取的数据,并且可能会使用调整后的参数进行自我调度 现在,在这个条件呈现False之后,我知道不会有任何新的输入项要处理 但是我怎么知道还没有

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

  • start()
  • start()
    调用另一个函数,让我们调用它
    get\u input()
  • get\u input()
    是一个协同程序,它通过网络获取一些数据,然后调度另一个协同程序,
    process\u input()
    ,将其添加为第一步添加的
    start()
  • get\u input()
    还检查某些条件,这些条件取决于所获取的数据,并且可能会使用调整后的参数进行自我调度
现在,在这个条件呈现
False
之后,我知道不会有任何新的输入项要处理
但是我怎么知道还没有解决的
get\u input()
process\u input()
的未来呢

我想这可以通过实现一种计数器来解决,每次调用
process\u input()
时,计数器都会递增,解析后会递减
但是如果有一系列不同的协同程序呢?我如何跟踪它们的状态,以便如果我停止IOLoop,任务在得到解决之前不会死亡

也许,应该有某种分级计数

编辑:

2@dano
好的,我现在明白了。。。我没有注意。您确实没有阻止,因为它自己的呼叫在此列表中
但是

  • 这种组织要求只使用
    产量
    构造,不使用
    添加回调
    ,否则我们将失去“等待”概念
  • 递归级别将增长。。嗯,不知道是不是太糟糕了
  • 我今天想到的是“元未来”
    我创建了一个空的
    Future()
    对象
    我用我的decorator修饰每个启用了
    @coroutine
    的方法,它增加“metafuture”中的计数器字段,并向它们的未来添加一个自定义完成的回调,这应该会减少它

    当它达到零时,“元未来”通过调用
    set\u result(None)
    还有一个IOLoop回调函数可以精确地生成该元未来:

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

    因此,在那之后,我们知道没有任何未来是悬而未决的。这是一种类似于手动实现refcounting的困难方法,但它涵盖了添加任务的
    IOLoop.add_callback()
    方法,您可以编写方法,使它们在所有工作完成之前不会返回,而不是安排回调。然后您可以只调用
    IOLoop.run\u 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)
    

    我们利用了这样一个事实,即协同程序返回
    未来
    ,并且Tornado支持这样一个事实,即我们可以尽可能多地并发运行,而无需从
    获取输入
    (因此
    开始
    )返回在完成所有相关工作之前。

    在完成处理之后,是否始终要停止IOLoop?或者是在带外停止IOLoop的请求,而您希望它在实际停止之前等待工作完成?@dano,据我所知,如果我调用
    IOLoop.stop()
    ,而某些未来仍未解决,它们将不会被处理。所以我假设我应该手动跟踪所有处理完成的时刻,然后
    stop()
    it这是真的
    IOLoop.stop()
    不会等待未完成的工作完成。但是,您可以组织应用程序,使其在完成工作后自动退出。很难说你不能真正了解你的程序是如何构造的。我知道龙卷风的这个特性,我实际上在另一个地方使用它。但是,如果我使用了
    yield[futures]
    get\u input()
    的执行会一直阻塞,直到它们完成为止,这会影响性能,因为我可以立即运行另一个
    get\u input()
    ,而无需等待进程输入()。这就是为什么我使用
    add_callback()
    来安排时间processing@Ojomio除了在
    start()
    内部调用一次,并在
    get\u input()
    自身内部递归调用一次之外,如何触发
    get\u input()
    ?我在示例中介绍了递归调用,它没有被
    process\u input
    阻止;它们并行运行。如果您在问题中添加一些示例代码,以准确显示您正在做的事情,这可能会有所帮助。。。我没有注意。你真的没有阻止,因为它自己的调用在这个列表中是
    yield fetch\u data\u over\u net()
    一个阻止调用?@user1045085它不会阻止IO循环,因为它是我们
    yield
    的一个协同程序,但它是“阻止”的,因为执行流将等待它完成,然后再转到下一行。