未来内部循环的状态始终处于待定状态

时间:2019-04-14 06:55:42

标签: python multithreading future python-asyncio

首先,我在jupyter笔记本上运行此程序,这可能是造成我困惑的原因。

我有一个执行某些IO操作的函数foo

def foo():
    # Dom some stuff
    time.sleep(1.)
    return 'Finished'

我希望能够在后台运行此功能,所以我决定使用run_in_executor

future = asyncio.get_event_loop().run_in_executor(None, foo)

现在操作是非阻塞的,一切都很好,但是如果这个将来返回一个错误,我想抓住它并停止主程序,因此我决定编写一个循环,以继续检查这个将来的状态:< / p>

while True:
    time.sleep(0.1)
    if future.done():
    # Do some stuff, like raising any caught exception

问题在于,将来的状态永远不会更改,在循环中,它始终待处理

如果不是手动检查循环,而是手动检查将来的状态(在jupyter笔记本中),它将被正确标记为已完成。这种行为使我感到困惑...

如何在循环公式中继续检查将来的状态?

1 个答案:

答案 0 :(得分:2)

run_in_executor设计用于asyncio,因此它的返回值是asyncio Future,由运行asyncio事件循环的线程操纵。由于您的代码在while循环中旋转而没有等待任何东西,因此它根本没有给事件循环运行的机会,从而有效地阻止了事件循环。未来仍然处于“待定”状态,因为应该更新的回调应该由事件循环调用,该事件循环目前尚不可用-它只是位于队列中。

time.sleep(0.1)替换await asyncio.sleep(0.1)可能会解决此问题。但是,您根本不需要while循环;由于异步的未来是可以等待的,因此您可以直接await将其进行:

await future
# Do some stuff, with the future done.

await暂停当前的协程,直到将来完成,这使其他任务有机会同时运行。它返回future的值,或传播异常。

另一种选择是根本不使用asyncio,而是直接使用concurrent.futures。这样,您将获得预期的线程语义(真正的“后台”执行)和相应的Future

# keep this in a global variable, so that the same executor
# is reused for multiple calls
executor = concurrent.futures.ThreadPoolExecutor()

# later, submit foo to be executed in the background
future = executor.submit(foo)

这个未来是concurrent.futures future,它支持这样的等待结果:

result = future.result()

此外,在这种将来,您的原始代码将保持不变。