概要
Python 3.5 引入 async 和 await 使得协程成为 Python 原生特征(native feature),引入这两个新语法的原因主要可以概括为下面几点:
Python 原来的协程是通过生成器实现的,所以它们两者拥有相同的语法,详见 PEP 342 – Coroutines via Enhanced Generators 和 PEP 380 – Syntax for Delegating to a Subgenerator。虽然生成器和协程是两个不同的概念,但是由于 Python 通过生成器实现协程,所以很容易认为生成器和协程是相同的。通过引入 async ,我们可以更好的区分生成器和协程,消除了二义性。
异步调用受限于 yield 表达式能出现的地方,即我们只能实现异步函数。通过引入 async ,我们可以定义异步 for 循环和异步上下文管理器。
一个函数是否是协程取决于函数体中是否有 yield 或者 yield from,这样会导致重构代码过程中引入不明显的bug。async 能减少重构代码导致的 bug
async
async 可以被用来定义一个原生协程,其语法如下:
>>>async defread_data(db):
...pass
...
>>>r = read_data(None)
>>>type(r)
coroutine
鉴于 Python 的生成器也可做协程来使用,我们需要先做一下区分:
原生协程函数 使用 async def 声明的协程函数,函数内部使用 await 表达式和 return 语句
原生协程 由原生协程函数返回的对象
基于生成器的协程函数 基于生成器语法的协程函数。
基于生成器的协程 由基于生成器的协程函数返回的对象
协程 既可以是原生协程又可以是基于生成器的协程
协程对象 既可以是原生协程对象又可以是基于生成器的协程对象
使用 async 定义的协程,协程性质可以总结如下:
使用 async def 声明的函数将总是成为协程,即使它们不包含 await 表达式。该函数将总是返回一个协程对象(coroutine object),类似于生成器和生成器对象。
在 async def 声明的函数中使用 yield 或者 yield from 表达式将得到SyntaxError。
原生协程内部基于生成器实现