我试图了解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"
也未打印。因此,取消未来永远不会退回到等待的任务上,这似乎合乎逻辑吗?但是,这些任务会永远坐在事件循环中吗?这似乎是不可取的,我在哪里误会了?
答案 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))