如何在Task Group的任务内部检测自身是否被取消?
如何在asyncio TaskGroup的任务内部检测自身被取消并执行清理?
根据asyncio TaskGroup的特性:组内任意任务抛出异常时,其余运行中的任务会被自动取消。但如果部分任务需要在被取消时执行清理操作,该怎么在任务内部检测到取消事件?
比如下面的代码,原本预期被取消的任务会触发异常并执行清理,但实际运行后并没有看到清理日志:
import asyncio class TerminateTaskGroup(Exception): """用于终止TaskGroup的异常""" async def task_that_needs_to_cleanup_on_cancellation(): try: await asyncio.sleep(10) except Exception: print('捕获到异常,执行清理...') async def err_producing_task(): await asyncio.sleep(1) raise TerminateTaskGroup() async def main(): try: async with asyncio.TaskGroup() as tg: tg.create_task(task_that_needs_to_cleanup_on_cancellation()) tg.create_task(err_producing_task()) except* TerminateTaskGroup: print('main() 处理终止逻辑') asyncio.run(main())
执行结果:
$ python3 script.py main() 处理终止逻辑
问题原因
你代码里用except Exception:捕获异常,但**asyncio.CancelledError并不属于Exception的子类**——它是专门用于标识任务被取消的异常,继承自BaseException,所以无法被Exception的捕获语句命中。
解决方法
要检测任务被取消,需要显式捕获asyncio.CancelledError,或者使用except BaseException:(不推荐,除非你需要处理所有类型的基础异常)。修改后的任务函数如下:
import asyncio class TerminateTaskGroup(Exception): """用于终止TaskGroup的异常""" async def task_that_needs_to_cleanup_on_cancellation(): try: await asyncio.sleep(10) except asyncio.CancelledError: print('任务被取消,执行清理操作...') # 若需要让TaskGroup正确感知任务取消状态,建议重新抛出该异常 raise except Exception: print('捕获到普通异常,执行清理...') async def err_producing_task(): await asyncio.sleep(1) raise TerminateTaskGroup() async def main(): try: async with asyncio.TaskGroup() as tg: tg.create_task(task_that_needs_to_cleanup_on_cancellation()) tg.create_task(err_producing_task()) except* TerminateTaskGroup: print('main() 处理终止逻辑') asyncio.run(main())
执行结果:
$ python3 script.py 任务被取消,执行清理操作... main() 处理终止逻辑
额外注意事项
- 如果清理操作是异步的,记得用
await调用对应的异步清理函数 - 捕获
CancelledError后,若不需要保留任务运行,建议重新抛出该异常,确保TaskGroup能正确处理任务的终止状态 - 避免滥用
except BaseException:,否则会意外捕获到SystemExit、KeyboardInterrupt等系统级异常,导致程序无法正常退出
内容的提问来源于stack exchange,提问作者laur
相关产品推荐
相关产品推荐

