Mini Asyncio 做什么、不做什么
前面的章节讲标准库怎么用。这里换个角度:自己写一个教学版事件循环。目标很小:把几个最容易糊成一团的点拆开,看看什么时候入队,什么时候等待,Future 怎么唤醒 Task。
项目位置:
text
examples/mini_asyncio_runtime/
├── mini_asyncio/
│ ├── __init__.py
│ └── core.py
├── demos/
└── tests/我们要保留什么
第一版只保留这些功能:
| 功能 | 它能帮你看见什么 |
|---|---|
EventLoop.run_until_complete() | 程序入口怎么把一个协程跑到结束 |
call_soon() | 先把 callback 放进队列,不急着马上执行 |
call_later() | sleep() 这类“过一会儿再继续”的等待怎么做 |
Future | 一个结果还没准备好时,先用什么占位 |
Task | 协程暂停后,之后怎么继续回来 |
sleep()、gather() | 常用 awaitable 是怎么拼出来的 |
sock_recv()、sock_send_all() | socket 可读可写时,怎么叫醒等待的人 |
AsyncQueue | 队列没数据时,消费者怎么睡着,生产者怎么叫醒它 |
我们故意不做什么
| 不实现 | 原因 |
|---|---|
| SSL、subprocess、signal | 细节太多,第一版会讲乱 |
| 标准库里的取消计数和异常组 | 第一版只演示怎么把取消抛进协程 |
| Transport/Protocol | 先直接用 socket,看起来更直 |
| 多事件循环 policy | 先只写一个 loop |
| 线程安全调度 | 先只考虑单线程 |
| Queue shutdown 的所有细节 | 先保留最小可用的 put/get/join |
它不能替代标准库,也不追求性能。代码越短越好,只要能说明 await、Future、Task、timer、selector 和 Queue 是怎么互相叫醒的。
跑起来是什么样
python
import mini_asyncio as aio
async def child(name, delay):
await aio.sleep(delay)
return name
async def main():
results = await aio.gather(
child("A", 0.2),
child("B", 0.1),
)
print(results)
aio.run(main())它会输出:
text
['A', 'B']顺序来自 gather 的输入顺序,不是完成顺序。
总体结构
怎么读这部分
读代码时可以按这个顺序:
- 先运行测试,确认项目可用。
- 看
Future,理解结果状态和回调。 - 看
Task._step,理解 coroutine 什么时候继续、什么时候停下。 - 看
EventLoop._run_once,理解 timer 到点和 socket 可读最后怎么变成 callback。 - 看
AsyncQueue,理解同步原语如何用 Future 唤醒等待者。