0

0

异步编程中:asyncio任务被取消时该捕获CancelledError还是Exception?

星夢妙者

星夢妙者

发布时间:2025-06-25 21:57:02

|

1106人浏览过

|

来源于php中文网

原创

应捕获 cancellederror 因为它专用于表示任务被取消,而捕获 exception 会误吞其他异常导致问题被隐藏。1. cancellederror 是 asyncio 设计用于明确标识任务取消的异常类型,可确保精准处理取消逻辑;2. 使用 try...except 捕获 cancellederror 并配合 finally 块可确保清理代码执行;3. 父任务取消时会传递取消子任务,但需等待其完成清理;4. 避免竞态条件可通过 asyncio.lock 保护共享状态。

异步编程中:asyncio任务被取消时该捕获CancelledError还是Exception?

取消 asyncio 任务,应该捕获 CancelledError。这是 asyncio 专门用来表示任务被取消的异常,捕获 Exception 可能会误捕获其他类型的错误,导致程序行为不符合预期。

异步编程中:asyncio任务被取消时该捕获CancelledError还是Exception?

asyncio 任务取消时,会抛出 CancelledError 异常。正确处理取消异常对于编写健壮的异步代码至关重要。

异步编程中:asyncio任务被取消时该捕获CancelledError还是Exception?

为什么应该捕获 CancelledError 而不是 Exception?

捕获 Exception 看起来像是“万能”解决方案,但实际上它会隐藏很多问题。考虑一个场景:你的任务在执行过程中可能因为网络问题抛出 TimeoutError,或者因为某些数据错误抛出 ValueError。如果你简单地捕获 Exception,那么这些原本应该被重视和处理的异常就被忽略了,你的程序可能会在不知情的情况下继续运行,导致更严重的问题。

CancelledError 是 asyncio 设计用来专门表示任务被取消的信号。捕获它,你可以精确地知道发生了什么,并采取相应的措施,比如清理资源、保存状态等。

异步编程中:asyncio任务被取消时该捕获CancelledError还是Exception?

如何正确处理 CancelledError?

一个常见的模式是在 try...finally 块中使用 try...except 来处理 CancelledErrorfinally 块可以确保即使任务被取消,清理代码也会被执行。

import asyncio

async def my_task():
    try:
        print("任务开始执行")
        await asyncio.sleep(5)  # 模拟耗时操作
        print("任务执行完成")
    except asyncio.CancelledError:
        print("任务被取消了!")
        # 在这里进行清理工作,例如关闭文件、释放资源等
    finally:
        print("无论如何都会执行的清理工作")

async def main():
    task = asyncio.create_task(my_task())
    await asyncio.sleep(1)  # 等待一段时间后取消任务
    task.cancel()
    try:
        await task  # 等待任务结束,会抛出 CancelledError
    except asyncio.CancelledError:
        print("main 函数也捕获了 CancelledError")

if __name__ == "__main__":
    asyncio.run(main())

在这个例子中,即使 my_taskasyncio.sleep(5) 期间被取消,finally 块中的清理代码仍然会被执行。同时,main 函数也捕获了 CancelledError,可以根据需要进行进一步的处理。

任务取消后,子任务会怎么样?

当一个 asyncio 任务被取消时,它的所有子任务也会被取消。这意味着取消操作会像多米诺骨牌一样,一层一层地传递下去。

AMiner
AMiner

AMiner——新一代智能型科技情报挖掘与服务系统,能够为你提供查找论文、理解论文、分析论文、写作论文四位一体一站式服务。

下载

但是,这里有一个需要注意的地方:子任务的取消并不意味着父任务可以立即结束。父任务仍然需要等待子任务完成取消操作,才能最终结束。

import asyncio

async def child_task():
    try:
        print("子任务开始执行")
        await asyncio.sleep(3)
        print("子任务执行完成")
    except asyncio.CancelledError:
        print("子任务被取消了!")
        await asyncio.sleep(1) # 模拟清理时间
        print("子任务清理完成")

async def parent_task():
    try:
        print("父任务开始执行")
        task = asyncio.create_task(child_task())
        await asyncio.sleep(1)
        print("父任务准备取消子任务")
        task.cancel()
        await task  # 等待子任务结束
        print("父任务等待子任务取消完成")
    except asyncio.CancelledError:
        print("父任务也被取消了!")

async def main():
    await parent_task()

if __name__ == "__main__":
    asyncio.run(main())

在这个例子中,当父任务取消子任务后,会等待子任务完成取消操作(包括执行 CancelledError 块中的清理代码)才会继续执行。

如何避免任务取消带来的竞态条件?

在复杂的异步程序中,任务取消可能会导致竞态条件。例如,一个任务可能在取消之前已经修改了共享状态,而取消后的清理代码又试图访问或修改这个状态。

为了避免这种情况,可以使用锁(asyncio.Lock)来保护共享状态。在访问或修改共享状态之前,先获取锁;在完成操作后,释放锁。这样可以确保在同一时刻只有一个任务可以访问共享状态,从而避免竞态条件。

import asyncio

async def task_a(lock):
    async with lock:
        # 访问或修改共享状态
        print("Task A acquired the lock")
        await asyncio.sleep(1)
        print("Task A releasing the lock")

async def task_b(lock):
    async with lock:
        # 访问或修改共享状态
        print("Task B acquired the lock")
        await asyncio.sleep(1)
        print("Task B releasing the lock")

async def main():
    lock = asyncio.Lock()
    task1 = asyncio.create_task(task_a(lock))
    task2 = asyncio.create_task(task_b(lock))

    await asyncio.sleep(0.5)
    task2.cancel()

    await asyncio.gather(task1, task2, return_exceptions=True)

if __name__ == "__main__":
    asyncio.run(main())

在这个例子中,task_atask_b 都试图访问共享状态,但它们必须先获取锁。如果 task_b 在获取锁之前被取消,那么它可以安全地退出,而不会影响 task_a 的执行。

总之,处理 asyncio 任务取消需要细致的考虑和严谨的编码。正确捕获 CancelledError,合理安排清理代码,并使用锁来保护共享状态,可以帮助你编写出更健壮、更可靠的异步程序。

相关专题

更多
高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

123

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

33

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

39

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

85

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

20

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

11

2026.01.15

ppt一键生成相关合集
ppt一键生成相关合集

本专题整合了ppt一键生成相关教程汇总,阅读专题下面的的文章了解更多详细内容。

47

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号