python asyncio 异常处理_python – 没有捕获asyncio.CancelledError

在本文中,我们将探讨Python asyncio中为何在某些情况下CancelError异常未被捕获的问题。通过一个示例,我们展示了如何在协程中正确处理CancelledError,以及为何在使用ensure_future时可能会遇到未启动的协程。解决方案包括使用await asyncio.sleep(0)来确保协程有机会开始执行,并了解在任务取消时如何进行资源清理。同时,文章提到了在处理asyncio任务时使用create_task的推荐做法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么在这个例子中没有捕获到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

This arranges for a CancelledError to be thrown into the wrapped

coroutine on the next cycle through the event loop. The coroutine then

has a chance to clean up or even deny the request using

try/except/finally.

解决方法:

问题是getter甚至没有开始执行,你可以通过在开头添加一个打印来确认.由于从未输入try块,因此except也没有运行.

发生这种情况是因为,与await相反,ensure_future不会立即开始执行协程,它只是将其调度为在下一个事件循环迭代中运行,就像call_soon对普通函数一样.由于您立即取消了该任务,因此它将从可运行集中删除,并且其协程将在未启动的情况下关闭.

在task.cancel()之前添加await asyncio.sleep(0),您应该观察到您期望的行为.我怀疑你不需要在你的实际代码中做出这样的改变 – 在不太可能的情况下,任务在它运行之前被取消,就像在例子中一样,它将没有机会获得尝试/除了清理的资源在第一位.

两条切线评论:

>您可能希望在处理后重新引发asyncio.CancelledError,否则将被禁止.如问题中所示,这不是getter中的问题,但如果代码隐藏在函数调用中,则可能是一个问题.更好的是,考虑使用finally或with,它传播异常并确保在不考虑异常类型的情况下释放资源.

>当您需要创建任务并运行协程时,loop.create_task为preferred到asyncio.ensure_future.简而言之,虽然两者都对协同程序做同样的事情,但create_task使意图更清晰; ensure_future旨在接受更广泛的对象并获得未指定类型的未来.

标签:python,python-asyncio

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值