创建时间: 2026-08-25最后更新: 2026-08-25

1. Future

在异步程序中,一个操作开始时,结果往往还没有准备好。例如,网络库已经发出了请求,但响应要稍后才能到达;某个底层回调已经注册,但回调什么时候触发还不确定。

等待方需要一个可以表达「结果将来会出现」的对象,这就是 asyncio.Future。

Future 本身不会执行网络请求,也不会启动一段协程。它只是保存一个尚未产生的结果,并在结果准备好时通知等待者。可以把参与者分成两端:

角色职责
生产者在未来设置结果、异常,或者取消 Future
等待者使用 await 等待 Future 完成
Future在两者之间保存状态和最终结果
future-basic.py
01
import asyncio
02
03
async def produce(future):
04
await asyncio.sleep(1)
05
06
if not future.cancelled():
07
future.set_result("数据已经准备好")
08
09
async def consume(future):
10
print("等待结果")
11
result = await future
12
print(result)
13
14
async def main():
15
loop = asyncio.get_running_loop()
16
future = loop.create_future()
17
18
producer = asyncio.create_task(produce(future))
19
await consume(future)
20
await producer
21
22
asyncio.run(main())

代码运行到 await future 时,如果 Future 尚未完成,当前的 consume Task 会暂停,并把执行机会交还给事件循环。事件循环继续推进 produce Task。生产者调用 set_result() 后,Future 进入完成状态,事件循环随后恢复等待它的 Task。

注意,set_result() 的职责是完成 Future,而不是在这一行直接跳进 consume() 继续执行。等待者由事件循环安排在后续调度机会中恢复。

Future 与前面学过的两个对象各自负责不同的事情:

对象表达的内容是否负责执行
协程对象一次异步调用否,需要被等待或调度
Task正在由事件循环推进的协程是
Future一个稍后才能确定的结果否

因此,不能把 Future 理解成一个「还没开始的任务」。它更像 Task 或底层异步操作正在等待的结果凭证。

2. 创建

在协程中创建 Future 时,推荐先取得当前事件循环,再调用 loop.create_future():

create-future.py
1
import asyncio
2
3
async def main():
4
loop = asyncio.get_running_loop()
5
future = loop.create_future()
6
7
print(future.done()) # False
8
9
asyncio.run(main())

虽然也能直接调用 asyncio.Future(),但 loop.create_future() 会明确地把 Future 绑定到当前事件循环,也允许第三方事件循环提供与自身适配的实现。因此,编写异步库和底层适配代码时应优先使用这种方式。

刚创建的 Future 处于未完成状态。创建它不会自动安排任何工作,如果没有其他代码负责完成它,下面的程序会一直等待:

unfinished-future.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
07
# 没有任何生产者调用 set_result()、set_exception() 或 cancel()
08
# await future # 将一直等待
09
10
asyncio.run(main())

这也解释了为什么普通业务代码很少需要手动创建 Future:Future 通常由网络库、驱动程序、事件循环适配层创建,业务代码只负责等待库返回的协程或 Task。

同一个 Future 可以被多个 Task 等待。Future 完成后,所有等待者都会取得同一个结果:

multiple-waiters.py
01
import asyncio
02
03
async def wait_result(name, future):
04
result = await future
05
print(f"{name} 收到:{result}")
06
07
async def main():
08
loop = asyncio.get_running_loop()
09
future = loop.create_future()
10
11
first = asyncio.create_task(wait_result("A", future))
12
second = asyncio.create_task(wait_result("B", future))
13
14
await asyncio.sleep(0.1)
15
future.set_result("完成")
16
17
await asyncio.gather(first, second)
18
19
asyncio.run(main())

Future 完成后会保留结果,所以还可以再次 await 它,新的等待不会让生产者重新执行:

await-future-again.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
future.set_result("已缓存的结果")
07
08
print(await future)
09
print(await future)
10
11
asyncio.run(main())

这和直接重复等待同一个协程对象不同。协程对象只能被完整执行一次,而完成后的 Future 可以反复读取同一个最终结果。

3. 状态

Future 创建后处于 pending,也就是未完成状态。之后只能走向三种终态之一:

状态如何进入等待时发生什么
正常完成set_result(value)await 返回 value
异常完成set_exception(error)await 抛出该异常
已取消cancel()await 抛出 CancelledError

正常、异常和取消都属于「已经完成」,所以这三种情况下 done() 都返回 True。终态不能再切换到其他状态,一个 Future 只能被完成一次。

future-state.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
07
print(future.done()) # False
08
print(future.cancelled()) # False
09
10
future.set_result("成功")
11
12
print(future.done()) # True
13
print(future.cancelled()) # False
14
print(future.result()) # 成功
15
16
asyncio.run(main())

常用状态方法如下:

方法含义
done()是否已经正常完成、异常完成或被取消
cancelled()是否最终进入取消状态
result()读取结果;失败时重新抛出异常
exception()读取异常;正常完成时返回 None
get_loop()取得 Future 所属的事件循环

如果 Future 还没有完成,直接调用 result() 或 exception() 会抛出 asyncio.InvalidStateError。在业务代码中,应优先使用 await future,因为 await 会在结果未准备好时暂停,而不是提前读取:

await-before-result.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
07
# future.result() # InvalidStateError
08
09
loop.call_later(1, future.set_result, "完成")
10
result = await future
11
print(result)
12
13
asyncio.run(main())

set_result() 和 set_exception() 也只能调用一次。如果 Future 已经完成或取消,再设置结果会抛出 InvalidStateError。生产者可能晚于取消请求返回结果时,应该先检查取消状态:

avoid-invalid-state.py
1
def complete(future, value):
2
if not future.cancelled():
3
future.set_result(value)

这项检查主要用于底层回调适配。普通业务代码不应到处用 done() 和 cancelled() 手写一套并发状态机。

4. 异常

生产者无法得到正常结果时,可以使用 set_exception() 完成 Future。等待者不需要检查某个特殊返回值,直接使用 try...except 处理异常:

future-exception.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
07
future.set_exception(ValueError("响应格式错误"))
08
09
try:
10
await future
11
except ValueError as error:
12
print(error)
13
14
asyncio.run(main())

如果不等待这个 Future,也没有调用 exception() 取走异常,事件循环可能在 Future 被回收时报告 Future exception was never retrieved。这通常说明程序启动了异步工作,却没有负责处理它的失败。

调用 future.cancel() 会尝试把未完成的 Future 标记为取消。等待它的代码会收到 asyncio.CancelledError:

cancel-future.py
01
import asyncio
02
03
async def main():
04
loop = asyncio.get_running_loop()
05
future = loop.create_future()
06
07
future.cancel("用户停止了等待")
08
09
try:
10
await future
11
except asyncio.CancelledError as error:
12
print(error)
13
14
print(future.done()) # True
15
print(future.cancelled()) # True
16
17
asyncio.run(main())

如果 Future 已经正常或异常完成,cancel() 不会覆盖原来的结果,并返回 False。如果取消成功,则返回 True。

当一个 Task 正在等待 Future,而这个 Task 被取消时,取消通常也会传播到它正在等待的 Future。取消不是普通的失败结果,而是异步调用链停止工作的控制信号;处理 CancelledError 时,完成资源清理后通常应该继续抛出。

5. 回调

Future 除了可以被 await,还可以通过 add_done_callback() 注册完成回调。回调只接收一个参数,也就是已经完成的 Future:

future-callback.py
01
import asyncio
02
03
def print_result(future):
04
if future.cancelled():
05
print("Future 已取消")
06
return
07
08
error = future.exception()
09
if error is not None:
10
print(f"执行失败:{error}")
11
return
12
13
print(f"收到:{future.result()}")
14
15
async def main():
16
loop = asyncio.get_running_loop()
17
future = loop.create_future()
18
future.add_done_callback(print_result)
19
20
future.set_result("消息")
21
print("结果已经设置")
22
23
await asyncio.sleep(0)
24
25
asyncio.run(main())

调用 set_result() 后,回调不会嵌套在这一行中立即执行,而是通过事件循环安排执行。即使注册回调时 Future 已经完成,回调也会被安排到后续调度机会。

对于普通业务流程,await 往往更直观。add_done_callback() 常见于底层库、监控逻辑和需要兼容回调接口的代码。

Future 最重要的用途之一,就是把旧式回调 API 转换成可等待的异步 API。假设一个旧函数通过回调返回错误或数据:

callback-adapter.py
01
import asyncio
02
03
def legacy_request(loop, callback):
04
loop.call_later(1, callback, None, {"name": "小微"})
05
06
async def request():
07
loop = asyncio.get_running_loop()
08
future = loop.create_future()
09
10
def on_complete(error, data):
11
if future.cancelled():
12
return
13
14
if error is not None:
15
future.set_exception(error)
16
else:
17
future.set_result(data)
18
19
legacy_request(loop, on_complete)
20
return await future
21
22
async def main():
23
result = await request()
24
print(result)
25
26
asyncio.run(main())

转换过程可以分成四步:

  1. 适配函数先创建一个 Future;
  2. 把回调交给旧 API;
  3. 回调触发后,用结果或异常完成 Future;
  4. 对外返回 await future 的结果。

调用者看到的是普通的 await request(),不再需要理解底层什么时候调用回调。Future 正是在这里连接了「回调世界」和 async / await 世界。

6. Task

Task 和 Future 都是可等待对象,都能保存最终结果、异常和取消状态,但它们的职责并不相同。

Task 是一种 Future 风格的对象,它在 Future 的状态能力之上增加了「推进协程」的职责。协程 return 的值会成为 Task 的结果,协程抛出的异常会成为 Task 的异常;调用者不能使用 set_result() 或 set_exception() 任意决定 Task 的结果。

task-and-future.py
01
import asyncio
02
03
async def fetch_user():
04
await asyncio.sleep(0.1)
05
return {"name": "小微"}
06
07
async def main():
08
task = asyncio.create_task(fetch_user())
09
10
print(asyncio.isfuture(task)) # True
11
print(await task) # {'name': '小微'}
12
print(task.result()) # {'name': '小微'}
13
14
asyncio.run(main())

asyncio.isfuture(task) 返回 True,说明 Task 符合 Future 协议,可以像 Future 一样被等待和检查状态。但 Task 的结果来源于协程执行,普通 Future 的结果则由外部生产者设置。

对比FutureTask
是否保存结果和异常是是
是否可以 await是是
是否主动推进协程否是
结果由谁决定外部生产者协程的 return 或异常
常见创建方式loop.create_future()asyncio.create_task()
主要使用位置异步库、驱动和回调适配层应用中的并发任务

当 Task 执行到 await future 时,可以把过程理解为:

  1. Task 检查 Future 是否完成;
  2. 如果尚未完成,Task 暂停;
  3. Future 记录这个等待关系;
  4. Future 完成后,事件循环让 Task 恢复;
  5. await 返回结果,或者在 Task 中抛出异常。

这条链路回答了一个关键问题:Task 被创建后并不是持续占用 CPU。它遇到尚未完成的 Future 时会暂停,事件循环可以去推进其他就绪 Task。

7. 边界

Future 是较底层的工具。编写普通 FastAPI 或 LangChain 业务时,通常应该返回协程的结果,而不是把裸 Future 暴露给调用者:

prefer-coroutine.py
01
import asyncio
02
03
async def load_user():
04
await asyncio.sleep(0.1)
05
return {"name": "小微"}
06
07
async def main():
08
user = await load_user()
09
print(user)
10
11
asyncio.run(main())

这样,Future 的创建、完成和取消都留在实现底层。调用者只需要使用稳定的异步函数接口。官方文档也建议,不要在面向业务使用者的 API 中直接暴露 Future。

ensure_future()

asyncio.ensure_future() 能接收 Future、Task、协程或其他可等待对象,并保证返回一个 Future 风格的对象:

ensure-future.py
01
import asyncio
02
03
async def work():
04
return "完成"
05
06
async def main():
07
task = asyncio.ensure_future(work())
08
print(await task)
09
10
asyncio.run(main())

如果参数本来就是 Future 或 Task,它会被直接返回;如果参数是协程,则会被包装成 Task 并安排执行。现代应用代码已经明确拿到协程时,通常优先使用语义更清楚的 asyncio.create_task();管理一组相关任务时,优先考虑 TaskGroup。

线程边界

asyncio.Future 不是线程安全对象。Future 应在它所属的事件循环线程中操作。如果工作在线程池或其他线程中完成,不应直接从那个线程调用 future.set_result(),而要使用线程安全的事件循环入口:

future-from-thread.py
01
import asyncio
02
import threading
03
04
def worker(loop, future):
05
result = "线程中的计算结果"
06
loop.call_soon_threadsafe(future.set_result, result)
07
08
async def main():
09
loop = asyncio.get_running_loop()
10
future = loop.create_future()
11
12
thread = threading.Thread(target=worker, args=(loop, future))
13
thread.start()
14
15
print(await future)
16
thread.join()
17
18
asyncio.run(main())

Python 还有另一种 concurrent.futures.Future,用于线程池和进程池。它与 asyncio.Future 不是同一个类型,不能直接在异步代码中 await。需要桥接已有的 concurrent.futures.Future 时,可以使用 asyncio.wrap_future();调用 asyncio.to_thread() 或事件循环的执行器 API 时,库通常已经替你处理了这层转换。

Promise 对比

Future 经常被类比为 JavaScript Promise,因为二者都表示未来的结果,但不能把它们当成完全相同的对象:

对比asyncio.FutureJavaScript Promise
是否表示未来结果是是
创建时是否自带执行器否new Promise(executor) 会立即调用执行器
谁完成结果外部生产者调用 Future 方法resolve 或 reject
完成后的调度由 asyncio 事件循环调度等待者和回调.then() 等进入微任务队列
是否线程安全否JavaScript 通常在自身事件循环模型中使用

因此,Future 只负责承载结果,不等于 JavaScript 中会立即运行 executor 的 Promise。Python 也不使用浏览器里的宏任务、微任务规则来解释 Future 的恢复顺序。

正在验证登录状态
请稍候,验证完成后将继续显示文章内容