script_rs = await future后,为啥future 和 script_rs类型不一样了?

为什么 script_rs = await future 执行后:

  • future 的类型是 CeleryFuture(自定义类)

  • script_rs 的类型却是 dict(Celery 任务的实际返回值)?


1. await future 的底层机制

在 Python 中,await 的关键行为由 __await__ 方法决定。对于 tornado.concurrent.FutureCeleryFuture 的父类):

  • await future 会等待 future 完成(通过 set_result 或 set_exception)。

  • 最终返回的是 future.result(),而不是 future 对象本身。

关键代码路径

# 在 BaseHandler.async_fetch 中
future = CeleryFuture()  # 类型: CeleryFuture
result = taskrunner.apply_async(args, **kwargs)  # 启动 Celery 任务
future.set_task_id(result.task_id)  # 绑定 Celery 的 AsyncResult
IOLoop.instance().add_callback(self._on_result, result, future)

# 在 _on_result 中
if result.ready():
    future.set_result(result.get())  # 将 Celery 任务的结果设置给 future
  • future.set_result(result.get()) 将 Celery 任务的返回值(如 {'loan_cv': 0.248})注入 CeleryFuture

  • await future 最终返回的是 set_result 传入的值,而非 future 对象。


2. 类型差异的根源

对象类型来源
future CeleryFuture 自定义类,继承自 tornado.concurrent.Future,用于包装 Celery 任务。
script_rs dict Celery 任务 executor.pyexec 的实际返回值,通过 future.set_result 注入。

关键点

  • CeleryFuture 是容器,用于管理异步状态和结果。

  • await 提取的是容器中的内容(即 set_result 设置的值),而非容器本身。


3. 类比理解

class Box:
    def __init__(self):
        self._content = None

    def set_content(self, content):
        self._content = content

    def __await__(self):
        yield  # 模拟异步等待
        return self._content

box = Box()
box.set_content({"name": "Alice"})  # 放入一个字典

async def demo():
    content = await box  # 返回的是 box._content,而非 box 对象
    print(type(box))     # <class '__main__.Box'>
    print(type(content)) # <class 'dict'>

# 输出:
# <class '__main__.Box'>
# <class 'dict'>
  • box 是容器(类型 Box),但 await box 返回的是 box._content(类型 dict)。

  • 这与 CeleryFuture 和 script_rs 的关系完全一致。


4. 你的代码中的证据

从日志可见:

self.log.debug(f"script_rs type:{type(script_rs)},, future type:{type(future)}")
# 输出: script_rs type:<class 'dict'>, future type:<class 'controller.base.CeleryFuture'>
  • future 是 CeleryFuture 实例,用于跟踪任务状态。

  • script_rs 是 Celery 任务返回的 dict,通过 future.set_result() 注入。


5. 总结

  • await future 返回的是 future 的结果值(由 set_result 设置),而非 future 对象本身。

  • CeleryFuture 是异步任务的包装器,而 script_rs 是任务的实际返回值。

  • 这种设计是异步编程的通用模式(如 Python 的 asyncio.Future、Tornado 的 Future 均遵循此规则)。

如果需要访问 future 对象本身(而不仅是结果),直接使用 future 变量即可,无需 await

posted @ 2025-06-24 19:33  郭慕荣  阅读(13)  评论(0)    收藏  举报