PEP 492 – Coroutines with async and await syntax为Python 3.5添加了通用的Coroutine支持。Coroutine是为了让书写异步代码像书写同步代码那样自然。
PEP 492有一个假设:
This PEP assumes that the asynchronous tasks are scheduled and coordinated by an Event Loop similar to that of stdlib module asyncio.events.AbstractEventLoop.
但是其实Python之前是已经具有Coroutine功能,可以使用yield或者yield from关键字从一个函数临时返回。但是采用yield的Coroutine一般是用来做Generator,也就是数据生成器。不是为了并发操作。而新引入的Coroutine是基于之前的Generator Coroutine实现的,但是主要是为了异步和并发。
在Python文档的3. Data model¶中,旧的,基于yield的coroutine被称为Generator functions,新的通用的Coroutine则称为Coroutine functions,然后基于新的Coroutine做成的generator叫做Asynchronous generator functions。
Generator functions和Coroutine functions类似,返回的iterator对象都具有以下方法,来与Coroutine的实例交互:
- send()
- throw()
- close()
不同的是,Generator functions返回的对象具有__next__()方法,可以遍历;而Coroutine functions返回的对象具有__await__()方法,是awaitable的(只能await一次)。然后Coroutine functions定义的时候必须加上async:
async def read_data(db):
data = await db.fetch('SELECT ...')
在上面的read_data函数中可以使用await关键字,但是不能使用yield。如果Coroutine没有被await,否则垃圾回收的时候就会出现RuntimeWarning异常。
使用types.coroutine()
可以把Generator functions修饰成Coroutine functions:
@types.coroutine
def process_data(db):
data = yield from read_data(db)
...
Coroutine functions都是awaitable的,普通对象也可以通过__await__()
来把自己变成awaitable。__await__()
必须返回一个iterator,否则就会产生TypeError。
使用async with可以产生一个异步的context manager。async with的使用对象必须具有__aenter__
和__aexit__
方法,两者都返回awaitable:
class AsyncContextManager:
async def __aenter__(self):
await log('entering context')
async def __aexit__(self, exc_type, exc, tb):
await log('exiting context')
也就是说,下面的语句:
async with EXPR as VAR:
BLOCK
会被改写成:
mgr = (EXPR)
aexit = type(mgr).__aexit__
aenter = type(mgr).__aenter__
VAR = await aenter(mgr)
try:
BLOCK
except:
if not await aexit(mgr, *sys.exc_info()):
raise
else:
await aexit(mgr, None, None, None)
相应的,也有async for语句,用于含有__aiter__
和__anext__
方法的对象:
class AsyncIterable:
def __aiter__(self):
return self
async def __anext__(self):
data = await self.fetch_data()
if data:
return data
else:
raise StopAsyncIteration
async def fetch_data(self):
...
New Standard Library Functions描述了针对标准库的改动,主要包括对inspect模块的修改,以及增加了sys.set_coroutine_wrapper(wrapper) 和sys.get_coroutine_wrapper()等调试功能。
collections.abc.Awaitable,collections.abc.Coroutine,collections.abc.AsyncIterable,collections.abc.AsyncIterator 为新增的抽象基类。
Design Considerations章节有一些对设计上取舍的描述。
其他参考
- PEP 3156 – Asynchronous IO Support Rebooted: the “asyncio” Module
- What does the “yield” keyword do?
- how to make python awaitable object
- asyncio awaitable object - basic example
- Is there ever a reason to
return await …
in python asyncio? - python - how to implement a C-function as awaitable (coroutine)
- How to make object awaitable in python 3.5?
- Python Docs: Coroutines and Tasks¶