取消异步的未来是否有用?

时间:2018-11-16 13:41:07

标签: future python-asyncio

我试图了解asyncio与Future.cancel()的使用。 Python文档对此非常重视。对于此处或搜索引擎上的现有问题,我没有获得成功。我只想了解当任务正在等待被取消的未来时发生的事情。

这是我的代码:

import asyncio 

async def foo(future):
    await asyncio.sleep(3)
    future.cancel()

async def bar(future):
    await future
    print("hi")

async def baz(future):
    await bar(future)
    print("ho")

loop = asyncio.get_event_loop()
future = loop.create_future()
loop.create_task(baz(future))
loop.create_task(foo(future))
loop.run_forever()

"hi"未打印。因此,我最初猜想bar在取消的情况下将返回await future行。

但是,"ho"也未打印。因此,取消未来永远不会退回到等待的任务上,这似乎合乎逻辑吗?但是,这些任务会永远坐在事件循环中吗?这似乎是不可取的,我在哪里误会了?

1 个答案:

答案 0 :(得分:1)

在这种情况下,答案就在文档中,但您需要一点点寻找。首先,提醒您等待一个未来的意义

# the expression:
x = await future

# is equivalent to:
... magically suspend the coroutine until the future.done() becomes true ...
x = future.result()

换句话说,一旦恢复执行包含await的协程,await语句的值将是等待的将来的result()

问题是:取消期货时,其结果是什么? documentation说:

  

如果Future已被取消,则此方法将引发CancelledError异常。

因此,当有人取消了您等待的未来时,await future表达式将引发异常!这很好地解释了为什么bar不打印hi(由于await future已提出),以及为什么baz不打印ho(因为{{1 }}已提出)。

永远不会打印回溯,因为await bar(...)在(各种)“背景”中生成协程-如果没有人检查返回值,则异常将丢失。而且,由于您丢弃了loop.create_task返回的task对象并使用create_task使循环永远运行,因此该循环继续运行,并(永远)等待新任务以某种方式到达。

如果您更改了代码以实际收集run_forever的结果,则很容易观察到bar

CancelledError

输出:

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    future = loop.create_future()
    loop.create_task(foo(future))
    loop.run_until_complete(baz(future))