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.Future(CeleryFuture 的父类):
-
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。

浙公网安备 33010602011771号