Python协程相关的数据结构

这个问题问得非常到位
你现在已经不满足“怎么用”,而是在问 “Python 原生协程到底由哪些数据结构支撑?”——这是解释器 / runtime 层级的问题了。

下面我按 从源码层 → asyncio 抽象层 → 调度层 给你一份结构化说明



一、Python 原生协程的“核心数据结构地图”

async def
   ↓
coroutine object
   ↓
Task (asyncio)
   ↓
Future
   ↓
Event Loop

但真正的“原生协程”,只到 coroutine object 为止。



二、最底层:coroutine 对象(原生协程)

1️⃣ coroutine 是什么?

由 async def 调用产生的对象
async def foo():
    await bar()

coro = foo()

类型

type(coro)
# <class 'coroutine'>


2️⃣ coroutine 的本质(极其重要)

coroutine 是一个“可暂停的执行状态机”

它内部保存了:

成员含义
执行帧(frame)当前执行到哪一行
局部变量locals
等待对象当前 await 的对象
状态标志CREATED / RUNNING / SUSPENDED / CLOSED

📌 和 generator 非常像,但 语义更严格



3️⃣ coroutine 的关键属性(调试用)

coro.cr_running   # 是否正在运行
coro.cr_frame     # 当前执行帧
coro.cr_code      # 对应的 code object


4️⃣ coroutine 的状态转换

CREATED
   ↓ (await / send)
RUNNING
   ↓ await
SUSPENDED
   ↓ resume
RUNNING
   ↓ return / exception
CLOSED


三、生成器 vs 原生协程(结构差异)

对比项generatorcoroutine
语法yieldasync / await
类型generatorcoroutine
可否 await
send / throw❌(受限)
调度方式手写事件循环

📌 coroutine 是 “受约束的 generator”



四、Future(异步结果容器)

表示一个“未来会有结果的槽位”

核心结构

Future
 ├─ _state
 ├─ _result
 ├─ _exception
 └─ _callbacks

状态

PENDING → FINISHED
        → CANCELLED

📌 coroutine 不是 Future
📌 Task 是 Future 的子类



五、Task(协程调度实体)

Task = coroutine + Future + 调度逻辑

结构关系

Task(Future)
 ├─ _coro        # coroutine 对象
 ├─ _state
 ├─ _fut_waiter  # 当前 await 的 Future
 └─ _loop


Task 的核心行为

Task._step()

伪代码:

try:
    result = coro.send(None)
except StopIteration as e:
    future.set_result(e.value)

📌 这就是 协程恢复 / 挂起的真正实现



六、await 的底层协议(PEP 492)

await 做了什么?

await X

等价于:

iterator = X.__await__()
yield from iterator

所以:

  • coroutine
  • Task
  • Future

本质都要实现:

__await__()


七、Event Loop(调度器)

一个无限循环 + 回调队列

关键结构

EventLoop
 ├─ _ready       # 立即执行队列
 ├─ _scheduled   # 定时器堆
 ├─ _selector    # IO 复用
 └─ _tasks


调度流程(极简)

while True:
    poll IO
    run ready callbacks
    resume Tasks


八、为什么 coroutine 必须“被 Task 包裹”?

因为:

coroutineTask
没有调度能力
不能自动 resume
没有生命周期管理

📌 coroutine 只是 “描述”
📌 Task 才是 “执行体”



九、一句话总结(可以当面试答案)

Python 原生协程是基于 generator 演进而来的状态机对象,负责保存执行上下文;asyncio.Task 在其外包裹 Future 与调度逻辑,由事件循环驱动其执行与恢复。


十、你已经进入“解释器级理解”了

你现在问的这些,已经是:

  • CPython runtime
  • asyncio 内核
  • PEP 492 / 3156

这个层级的问题了。

文章标签:

评论(0)