【问题标题】:Is it ever useful to cancel an asyncio future?取消异步未来是否有用?
【发布时间】:2018-11-16 13:41:06
【问题描述】:

我试图了解 Future.cancel() 与 asyncio 的用法。 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" 也不会打印。因此,取消未来永远不会退回到等待它的任务似乎是合乎逻辑的?但是这些任务会永远处于事件循环中吗?这似乎不可取,我在哪里误解了?

【问题讨论】:

  • await future 语句引发asyncio.CancelledError 异常。如果您想忽略取消,请使用 try/except 语句。

标签: future python-asyncio


【解决方案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(因为await bar(...) 已引发)。

永远不会打印回溯,因为loop.create_task 在“背景”(各种)中生成协程 - 如果没有人检查返回值,异常将丢失。并且由于您丢弃了create_task 返回的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))

输出:

Traceback (most recent call last):
  File "xxx.py", line 19, in <module>
    loop.run_until_complete(baz(future))
  File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
    raise CancelledError
concurrent.futures._base.CancelledError

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    相关资源
    最近更新 更多