Python asyncio future add_done_callback 然后取消 future

Python asyncio future add_done_callback then cancel the future

我无法理解 asyncio 的工作原理 如果我创建一个未来 future = asyncio.Future() 然后添加 add_done_callback(done_callback) 然后取消未来 future.cancel() done_callback 不会被解雇吧? 我尝试使用 loop.run_forever() 但我最终陷入了无限循环。

我有一个小示例代码:

_future_set = asyncio.Future()


def done_callback(f):
    if f.exception():
        _future_set.set_exception(f.exception)
    elif f.cancelled():
        _future_set.cancel()
    else:
        _future_set.set_result(None)

async def check_stats(future):
    while not future.cancelled():
        print("not done")
        continue
    loop.stop()

def set(future):
    if not _future_set.done():
        future.add_done_callback(done_callback)


loop = asyncio.new_event_loop()
future = loop.create_future()

asyncio.ensure_future(check_stats(future), loop=loop)

set(future)
future.cancel()
loop.run_forever()  # infinite
print(_future_set.cancelled())

我知道缺少某些东西,也许这不是行为,但我很乐意在这里提供一点帮助。

我正在使用 python 3.6

**更新 设置为火后,我将 add_done_callback 绑定到未来 当我取消未来并且未来状态更改为取消并完成时,我希望 _future_set 也将被取消。 print(_future_set.cancelled()) 将是 True

来自文档字符串(在我的 unix 系统上)help(loop.run_forever):

  run_forever() method of asyncio.unix_events._UnixSelectorEventLoop instance
    Run until stop() is called.

当您调用 loop.run_forever() 时,程序将不会超出该行,直到在 ioloop 实例上调用 stop(),并且您的代码中没有任何内容这样做。

loop.run_forever() 本质上是在做:

def run_forever(self):
    while not self.stopped:
        self.check_for_things_to_do()

如果不多了解您要实现的目标,就很难进一步帮助您。然而,您似乎期望 loop.run_forever() 在 python 代码的执行中是异步的,但事实并非如此。 IOLoop 将继续循环并检查 filevents 并触发 futures 回调,并且只会 return 返回到它被告知停止循环时调用的点。


啊,我现在明白你的期望了。您需要通过 future = loop.create_future()future = asyncio.Future(loop=loop) 向 ioloop 注册期货。前者是 the preferred method 用于创建期货。 N.B.loop.run_forever() 调用时代码仍将永远 运行 除非它被停止,所以你的打印语句将永远不会到达。


进一步的附录:如果您实际上 运行 您问题中的代码,则会在 f.exception() 处引发异常,即 as per the docs:

exception()

Return the exception that was set on this future.

The exception (or None if no exception was set) is returned only if the future is done. If the future has been cancelled, raises CancelledError. If the future isn’t done yet, raises InvalidStateError.

这意味着 done_callback() 的调用在第一个 if f.exception() 处停止。所以如果你切换 done_callback() 来阅读:

def done_callback(f):
    if f.cancelled():
        _future_set.cancel()
    elif f.exception():
        _future_set.set_exception(f.exception)
    else:
        _future_set.set_result(None)

然后你得到预期的输出。