代码之家  ›  专栏  ›  技术社区  ›  jsstuball

取消异步IO将来是否有用?

  •  0
  • jsstuball  · 技术社区  · 7 年前

    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" 也没有打印。因此,取消一个未来永远不会让等待它的任务退却似乎是合乎逻辑的?但是这些任务永远都在事件循环中?这似乎不可取,我哪里误解了?

    1 回复  |  直到 7 年前
        1
  •  4
  •   user4815162342    7 年前

    在这种情况下,答案在文档中,但您必须稍微查找一下。首先,提醒你这对你意味着什么 等待

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

    换句话说,一旦执行包含 await 声明将是 result() 期待已久的未来。

    documentation 说:

    如果未来是 取消 ,此方法会引发 CancelledError

    因此,当有人取消了你期待的未来时 await future 表达式将引发异常!这很好地解释了原因 bar 不打印 hi 等待未来 baz 不打印 ho (因为 await bar(...) 已提出)。

    回溯永远不会打印,因为 loop.create_task 在“后台”(排序)中生成协同程序-如果没有人检查返回值,异常将丢失。既然你扔掉了 task 返回的对象 create_task run_forever 为了让循环永远运行,循环只是继续运行,等待(永远)新任务以某种方式到达。

    酒吧 取消错误

    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