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

asyncio.CancelledError没被抓住

  •  4
  • VPfB  · 技术社区  · 8 年前

    为什么 CancelledError 在这个例子中没有被抓住?

    import asyncio
    
    q = asyncio.Queue()
    
    async def getter():
        try:
            v = await q.get()
            print(f"getter got {v}")
        except asyncio.CancelledError:
            print("getter cancelled")
    
    async def test():
        task = asyncio.ensure_future(getter())
        task.cancel()
        await task
    
    def main():
        loop = asyncio.get_event_loop()
        loop.run_until_complete(test())
    
    if __name__ == '__main__':
        main()
    

    我希望得到“getter cancelled”消息,但收到了堆栈跟踪:

    Traceback (most recent call last):
      File "ce.py", line 22, in 
        main()
      File "ce.py", line 19, in main
        loop.run_until_complete(test())
      File "/usr/lib64/python3.6/asyncio/base_events.py", line 468, in run_until_complete
        return future.result()
    concurrent.futures._base.CancelledError
    

    Task.cancel 国家:

    这将安排一个CancelledError被扔进 有机会清理甚至拒绝使用 尝试/排除/最后。

    1 回复  |  直到 8 年前
        1
  •  6
  •   user4815162342    8 年前

    问题是 getter 正在执行,您可以通过在开始处添加打印来确认。自从 try 街区从未进入 except 也没跑。

    这是因为 await ensure_future 不会立即开始执行协程,它只是将其安排在下一个事件循环迭代中运行,如 call_soon 用于普通功能。由于您立即取消该任务,它将从可运行集中移除,并且它的协程将在从未启动的情况下关闭。

    添加 await asyncio.sleep(0) task.cancel()

    两个相切的注释:

    • 你可能想重新养大 asyncio.CancelledError 吸气剂 如问题中所示,但如果代码隐藏在函数调用中,则可能是一个问题。更好的是,考虑使用 finally with

    • 当您需要创建任务并运行协同程序时, loop.create_task preferred asyncio.ensure_future . 简言之,虽然两人都做同样的事情来共游, create_task 确保未来 旨在接受范围更广的对象并获得未指定类型的未来。