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

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)都支持,但它们的执行上下文和异常传播机制不同。
-
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 的核心概念和高级技巧!











