asyncio.future 是一个可等待的占位符对象,非协程也不执行异步逻辑;它需手动 set_result()/set_exception() 才完成,而协程返回值由事件循环自动调度执行并返回。

asyncio.Future 是什么,和协程返回值有什么区别?
asyncio.Future 是一个可等待(awaitable)的对象,但它本身不是协程,也不执行任何异步逻辑。它更像一个“占位符”:你创建它,稍后手动 set_result() 或 set_exception(),所有 await 它的地方就会立刻解阻塞并拿到结果。
和 await some_coro() 不同,await 一个 Future 不会触发调度或 IO,只是等它被标记为“完成”。常见于桥接回调式 API(比如网络库的 on_connect 回调)、测试 mock、或实现自定义 awaitable 控制流。
注意:Future 必须在同一个事件循环中创建和设置,否则会报 InvalidStateError 或静默失败。
怎么手动设置 Future 的结果?
核心就两步:创建 + 设置。但必须确保事件循环正在运行,且设置动作发生在 loop 线程内(通常用 loop.call_soon_threadsafe() 跨线程安全调用)。
常见写法:
import asyncio
<p>loop = asyncio.get_event_loop()
fut = loop.create_future()</p><h1>✅ 正确:在 loop 线程内设置</h1><p>loop.call_soon(lambda: fut.set_result("done"))</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4102" title="Shadows Python Sensei"><img
src="https://img.php.cn/upload/skill/000/000/081/178990406882325.jpg" alt="Shadows Python Sensei" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill4102" title="Shadows Python Sensei" class="overflowclass">Shadows Python Sensei</a>
<p class="overflowclass">Python 最佳实践助手——代码规范、设计模式、性能优化、测试与类型注解。适用于编写或审查 Python 代码。</p>
</div>
<a rel="nofollow" href="/xiazai/skill4102" title="Shadows Python Sensei" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>❌ 错误:直接 set_result() 可能触发 InvalidStateError</h1><h1>fut.set_result("done") # 可能报错,尤其 loop 未启动时</h1><p>result = await fut # 返回 "done"
</p>
-
set_result(value):仅当fut.done() == False时可用;多次调用会抛InvalidStateError -
set_exception(exc):让 await 抛出该异常,效果等价于协程中raise exc -
cancel():标记为取消,后续 await 会抛CancelledError;已 set_result/set_exception 后再 cancel 无效
为什么不能直接用 asyncio.ensure_future(my_coro())?
asyncio.ensure_future() 是把协程对象包装成 Task(继承自 Future),让它自动加入事件循环调度。它不给你手动控制权 —— 你无法中途 set_result(),也不能在协程还没 yield 前就“提前完成”。
而 loop.create_future() 给你的是裸的 Future,完全空转,全靠你驱动。典型场景:
- 封装基于回调的底层库(如
socket.setblocking(False)+select) - 实现超时重试逻辑:先创建 fut,启动子任务,超时时
fut.set_exception(TimeoutError()) - 测试中模拟“某个异步操作将在未来某刻完成”,避免真实 IO
容易踩的坑:done()、result()、exception() 的调用时机
Future 的状态流转是单向的:pending → done(含 success / failed / cancelled)。一旦 done() 返回 True,才能安全调用 result() 或 exception();否则会抛 InvalidStateError。
所以不要这样写:
# ❌ 危险:没检查是否 done 就取 result
print(fut.result()) # 可能崩溃
<h1>✅ 安全写法(仅用于调试,生产环境应 await)</h1><p>if fut.done():
print(fut.result())
else:
print("not ready yet")
</p>
更关键的是:即使 fut.done() 为 True,如果它是被 cancel() 的,fut.result() 仍会抛 CancelledError。所以真正健壮的取值逻辑是:
try:
res = fut.result()
except CancelledError:
print("was cancelled")
except Exception as e:
print("failed with", e)
跨线程设置 Future 是高频出错点:务必用 loop.call_soon_threadsafe(fut.set_result, ...),而不是直接调用。漏掉这层,程序可能卡死或行为不可预测。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










