码迷,mamicode.com
首页 > 编程语言 > 详细

Python 3.5的async和await特性(PEP492翻译)

时间:2015-06-23 23:23:53      阅读:458      评论:0      收藏:0      [点我收藏+]

标签:


原因:

 1,coroutine容易与正常的generators弄混

 2,一个function是否为coroutine由函数体内是否有yield 或者yield from 决定,这不科学。

 3,如果在语法上允许yield的地方才能进行异步调用,那诸如with和for语句中都不能执行异步了。

咋解决呢,把coroutine当成一个native的Python语言特性,与generator完全独立。

Native coroutines及其新的语法使得在异步条件下定义context manager(上下文管理器)和iteration protocols(迭代器协议)成为可能(也就是with和for了)。

通过 async with语句可以使得Python程序在进入和退出runtime context(运行时上下文)时,执行异步调用;

通过 async for 语句使得可以在迭代器中执行异步调用。(老外真是的,老是 make it possible).

 

语法定义

假定你已经知道:

 * Python中coroutines的实现。 implementation of coroutines in Python ( PEP 342 and PEP 380 ). 

 * 一些要被改变的语法来自asyncio框架和"Cofunctions"提议(已经悲剧了)。Motivation for the syntax changes proposed here comes from the asyncio framework ( PEP 3156 ) and the "Cofunctions" proposal ( PEP 3152 , now rejected in favor of this specification).

新定义的coroutine

async def read_data(db):
    pass

native couroutines的关键特性:

* 使用async def定义的函数总是native coroutine,无论其中是否有await表达式。

* async函数中不允许有yield和yield from,将抛出SyntaxErro异常。

* 在内部呢,引入了两个新的code object flags. 

     -- CO_COROUTINE用于标记native corroutine(也就是通过async def 定义的)

     -- CO_ITERABLE_COROUTINE 用于的基于 生成器的coroutine与native coroutines兼容。

   所有的coroutine对象都有CO_GENERATOR标准。

* generator返回generator object, coroutines 返回 coroutine object

* 没有被await on的coroutine在gc时会抛出RuntimeWarning 。

Await表达式

await表达式用于获取一个coroutine的执行结果。

async def read_data(db):
    data = await db.fetch(‘SELECT ...‘)
    ...

await,与yield from类似(译注;其实知道的真是不多),将阻塞read_data的执行,直到db.fetch这一awaitable的完成并返回数据。

awaitable(注:主要这个awaitable是名词,不是形容词)可以是: 

1, 从一个native coroutine函数返回的native coroutine object.

2, 以types.coroutine 装饰的(decorated) 生成器函数返回的generator-based coroutine object。

3,一个对象,该对象的__await__方法返回一个迭代器。

    如果__await__返回的不是iterator,则抛出TypeError。

4,CPython的C API定义 tp_as_async->am_await函数。

    如果await出现在async def函数以外,则抛出Syntax Error;

 将awaitable对象以外的任何东西传递给await表达式都会抛出TypeError。

。。。。。。。。。

...忽略严格的语法定义部分...

。。。。。。。。

await表达式的优先级高于**,低于切片[]、函数调用()和attribute reference(属性引用,如x.attribute),


Asynchronous Context Managers and "async with"

asynchronous context manager(异步上下文管理器)是能够在enter和exit方法中阻塞(当前coroutine)执行的上下文管理器。又增加了两个魔力函数:__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__(mgr)
exc = True

VAR = await aenter
try:
    BLOCK
except:
    if not await aexit(mgr, *sys.exc_info()):
        raise
else:
    await aexit(mgr, None, None, None)

和通常的with语句一样,可以在一个await with语句中指定多个上下文管理器。

Example

使用异步上下文管理器可以很容易的实现用于数据库事务管理器的coroutine. 

With asynchronous context managers it is easy to implement proper database transaction managers for coroutines:

async def commit(session, data):
    ...

    async with session.transaction():
        ...
        await session.update(data)
        ...

需要加锁的代码变得更加清晰:Code that needs locking also looks lighter:

async with lock:
    ...

instead of:

with (yield from lock):
    ...


异步迭代器和"async for"

asynchronous iterable能够在其iter实现中调用异步代码,并且能够在其next方法中调用异步代码。

* 必须实现__aiter__方法,该方法返回一个awaitable,并且该awaitable的结果必须 是一个asynchronous iterator object。An object must implement an __aiter__ method returning an awaitable resulting in an asynchronous iterator object .

* asynchronous iterator object必须实现 __anext__ 成员函数,该成员函数返回 awaitable对象 ;

 * 为停止迭代,__anext__必须抛出StopAsyncIteration 异常。

举个例子:

class AsyncIterable:
    async 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):
        ...

新语法

A new statement for iterating through asynchronous iterators is proposed:

async for TARGET in ITER:
    BLOCK
else:
    BLOCK2

等价于:

iter = (ITER)
iter = await type(iter).__aiter__(iter)
running = True
while running:
    try:
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration:
        running = False
    else:
        BLOCK
else:
    BLOCK2

如果用于async for的迭代器没有__aiter__ 成员函数,将抛出TypeError; 

如果在async def函数以外使用async for将抛出SyntaxError错误。

如同通常的 for语句,async for也有可选的else子句。


Python 3.5的async和await特性(PEP492翻译)

标签:

原文地址:http://my.oschina.net/cppblog/blog/469926

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!