原标题:用Python3的async/await做异步编程
前年我曾写过一篇《初探 Python 3 的异步 IO 编程》,当时只是初步接触了一下 yield from 语法和 asyncio 标准库。前些日子我在 V2EX 看到一篇《为什么只有基于生成器的协程可以真正的暂停执行并强制性返回给事件循环?》,激起了我再探 Python 3 异步编程的兴趣。然而看了很多文章和,才发现极少提到 async 和 await 实际意义的,绝大部分仅止步于对 asyncio 库的使用,真正有所帮助的只有《How the heck does async/await work in Python 3.5?》和《A tale of event loops》这两篇。
在接着写下去之前,我先列举一些 PEPs 以供参考:
PEP 255 — Simple Generators
PEP 342 — Coroutines via Enhanced Generators
PEP 380 — Syntax for Delegating to a Subgenerator
PEP 492 — Coroutines with async and await syntax
PEP 525 — Asynchronous Generators
从这些 PEPs 中可以看出 Python 生成器 / 协程的发展历程:先是 PEP 255 引入了简单的生成器;接着 PEP 342 赋予了生成器 send() 方法,使其可以传递数据,协程也就有了实际意义;接下来,PEP 380 增加了 yield from 语法,简化了调用子生成器的语法;然后,PEP 492 将协程和生成器区分开,使得其更不易被用错;最后,PEP 525 提供了异步生成器,使得编写异步的数据产生器得到简化。
本文将简单介绍一下这些 PEPs,着重深入的则是 PEP 492。
首先提一下生成器(generator)。
Generator function 是函数体里包含 yield 表达式的函数,它在调用时生成一个 generator 对象(以下将其命名为 gen)。第一次调用 next(gen) 或 gen.send(None) 时,将进入它的函数体:在执行到 yield 表达式时,向调用者返回数据;当函数返回时,抛出 StopIteration 异常。在该函数未执行完之前,可再次调用 next(gen) 进入函数体,也可调用 gen.send(value) 向其传递参