PEP 0492 - Python 3.5 异步关键字

PEP 0492 - Python 3.5 async keyword

PEP 0492async 关键字添加到 Python 3.5。

Python 如何从使用此运算符中获益?协程的例子是

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

根据文档,这实现了

suspend[ing] execution of read_data coroutine until db.fetch awaitable completes and returns the result data.

这个 async 关键字是否真的涉及创建新线程或可能使用现有的保留异步线程?

如果 async 确实使用了保留线程,它是否是一个单独的共享线程?

不,协程不涉及任何类型的线程。协同例程允许 合作 多任务处理,因为每个协同例程都自愿放弃控制。另一方面,线程在任意点的单位之间切换。

在 Python 3.4 之前,可以使用 generators 编写协程;通过在函数体中使用 yieldyield from 表达式,您创建了一个生成器对象,其中代码仅在您迭代生成器时执行。与其他事件循环库(例如 asyncio)一起,您可以编写协同例程,向事件循环发出信号,表明它们将要忙(可能正在等待 I/O),并且另一个协同例程同时例程可以是运行:

import asyncio
import datetime

@asyncio.coroutine
def display_date(loop):
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        yield from asyncio.sleep(1)

每次上面的代码前进到yield from asyncio.sleep(1)行,事件循环就自由运行一个不同的协程,因为这个例程下一秒不会做任何事情无论如何.

因为生成器可以用于各种任务,而不仅仅是协同例程,而且因为使用生成器语法编写协同例程可能会让新手感到困惑,所以 PEP 引入了新的语法,使其成为 更清楚你在写协程。

随着 PEP 的实施,上面的示例可以改写为:

async def display_date(loop):
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(1)

生成的coroutine对象仍然需要一个事件循环来驱动协程;事件循环将依次 await 在每个协同例程上,这将执行那些当前 await 未完成某些事情的协同例程。

优点是有了原生支持,你还可以引入额外的语法来支持异步上下文管理器和迭代器。进入和退出上下文管理器,或遍历迭代器然后可以成为您的协同例程中的更多点,表明其他代码可以 运行 而不是因为有东西再次等待。