Python怎么给异步任务添加回调_使用add_done_callback处理结果

秋墨君_9115

秋墨君_9115

2026-06-07

834人浏览

原创

add_done_callback收不到返回值,因回调只接收future对象,需调用future.result()获取结果;须用try/except捕获cancellederror和异常;非future对象或被回收会导致回调不触发。

python怎么给异步任务添加回调_使用add_done_callback处理结果

add_done_callback 为什么收不到返回值?

因为 add_done_callback 的回调函数只接收一个参数:已完成的 Future 对象,不是任务的返回值本身。你得手动调用 future.result() 才能拿到结果,直接打印 future 看到的是对象地址,不是你想要的数据。

常见错误写法:def on_done(future): print(future) —— 这只会输出类似 <future at state="finished" returned int></future>,毫无实用价值。

  • 正确做法是:在回调里调用 future.result()(注意可能抛出异常)
  • 如果任务被取消,future.result() 会抛 CancelledError;如果执行出错,会原样抛出任务里的异常
  • 不要在回调里做耗时或阻塞操作(比如同步 HTTP 请求、time.sleep),否则会拖慢事件循环调度

asyncio.create_task 和 ThreadPoolExecutor.submit 的 callback 行为一样吗?

不一样。add_done_callback 是 Future 类的方法,所有继承自 Future 的对象(包括 asyncio.Task 和 concurrent.futures.Future)都支持,但它们的执行上下文和异常传播机制不同。

python-parallelization
python-parallelization

将顺序 Python 代码转换为并行/并发实现,用于在需要并行化 Python 代码、提升性能时使用。

下载
  • asyncio.Task 的回调在事件循环线程中执行,可安全 await 其他协程(但回调函数本身不能是 async 函数)
  • concurrent.futures.Future(如 ThreadPoolExecutor.submit().add_done_callback(...))的回调在工作线程中执行,不能直接 await 协程,需用 asyncio.run_coroutine_threadsafe() 转发到事件循环
  • 两者都不支持返回值传递给下一个回调,链式处理需自己封装逻辑

回调里怎么安全获取结果并处理异常?

别裸奔调用 future.result()。必须用 try/except 包裹,因为异步任务失败时异常不会自动打印,也不会中断主线程,容易静默丢失问题。

def handle_result(future):
    try:
        result = future.result()  # 这里才真正取值或触发异常
        print("Success:", result)
    except asyncio.CancelledError:
        print("Task was cancelled")
    except Exception as e:
        print("Task failed:", type(e).__name__, str(e))
  • 即使你确认任务不会失败,也建议保留基础异常捕获,避免回调崩溃导致后续回调不执行
  • 如果想区分“任务未完成”和“任务失败”,可用 future.done() 先判断状态
  • 注意:future.exception() 只返回异常对象(不抛出),适合仅需检查错误类型而不中断流程的场景

为什么回调有时根本不触发?

最常见原因是:你给的对象根本不是 Future 实例,或者它已经被垃圾回收了。比如直接对协程对象调用 add_done_callback,会报 AttributeError: 'coroutine' object has no attribute 'add_done_callback'。

  • 确保传入的是 asyncio.create_task(...) 或 loop.create_future() 返回的 Task/Future
  • 避免把回调加在刚创建但还没被调度的 Task 上后立刻丢弃引用——Python 可能提前回收它(尤其在测试脚本中)
  • 在 asyncio.run() 结束前没 await 或没 keep reference,Task 可能被取消或清理,回调失效
  • 调试技巧:在回调开头加 print("callback fired"),配合 logging 查看是否进入;用 future.cancelled() 或 future.done() 检查状态

回调本身不参与事件循环调度优先级,也不受 timeout 控制,它只是“通知机制”。真正容易被忽略的是:你无法从回调里改变任务的生命周期,也不能靠它来实现依赖调度——需要链式任务,请用 await 或 asyncio.gather,而不是堆 callback。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1711

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4324

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1689

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

25277

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3087

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3107

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1163

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2403

5

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程