8.16. 小结¶
你已经走完了 asyncio 的 API——脚本在单个 CPU 上并发运行多个任务所需的各个部件:
协作式调度——本模块其余内容所依赖的模型。正在运行的协程独占事件循环,直到它
await;切换只发生在那些 await 处。协程与任务——
async def定义一个工作单元;asyncio.create_task()并发地调度一个工作单元,并返回一个Task,应用程序之后可以对它进行等待、取消或识别。事件循环——运行协程和任务的引擎。
asyncio.run()是大多数脚本所需的唯一入口点;Loop类为需要它的少数情况暴露了其余功能。协调——
gather()用于扇出和扇入,wait_for()用于截止时间,Task.cancel以及finally子句的清理模式,异常在任务和 gather 调用中的传播,还有事件循环的异常处理程序钩子。同步原语——
Event用于协程之间的信号传递,Lock用于跨 await 串行化对共享资源的访问,ThreadSafeFlag用于从中断处理程序唤醒一个 asyncio 任务。自定义异步对象——让应用程序类能够接入 asyncio 惯用法的语言钩子。
__await__用于那些本身就是await目标的对象,__aiter__/__anext__用于async for,__aenter__/__aexit__用于async with。帧捕获——把
csi.CSI.snapshot()转换为对await友好的协程的包装器,使得一个捕获循环可以与其他 asyncio 工作并行运行。陷阱——遗忘的
await、没有让出的紧密循环、被吞掉的取消、跨 await 被改动的共享状态,以及其余 asyncio 特有的陷阱。
这已经足以编写在同一个事件循环上混合摄像头工作、硬件 I/O 和并发后台工作的程序了。
8.16.1. 稍后使用本参考¶
把 asyncio 各章当作参考资料;回来查阅 async with 的写法或 gather() 在某个同级任务失败时的确切行为,正是它们的预期用途。当问题只是“这个调用的确切名称是什么”时,asyncio 参考页在一处列出了每个函数和类。
对于构建在本模块之上的更丰富的原语——信号量、队列、屏障,以及大量面向应用的辅助工具——peterhinch/micropython-async 仓库是社区维护的标准来源。
8.16.2. 下一步去往何处¶
网络是下一个重要主题。asyncio.open_connection()、asyncio.start_server() 以及 Stream 类是 asyncio 脚本从协程内部与网络其余部分通信的方式,再加上底层的 network 和 socket 模块。你学到的关于 await、Task、取消以及同步原语的一切都可以直接沿用。