Skip to content

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 的输入顺序,不是完成顺序。

总体结构

怎么读这部分

读代码时可以按这个顺序:

  1. 先运行测试,确认项目可用。
  2. Future,理解结果状态和回调。
  3. Task._step,理解 coroutine 什么时候继续、什么时候停下。
  4. EventLoop._run_once,理解 timer 到点和 socket 可读最后怎么变成 callback。
  5. AsyncQueue,理解同步原语如何用 Future 唤醒等待者。

面向学习目的的 Python asyncio 中文教程与 mini_asyncio 教学运行时。