首先,我在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笔记本中),它将被正确标记为已完成。这种行为使我感到困惑...
如何在循环公式中继续检查将来的状态?
答案 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()
此外,在这种将来,您的原始代码将保持不变。