@asyncio.coroutine 与异步 def

问题描述 投票:0回答:4

随着我见过的

asyncio
图书馆,

@asyncio.coroutine
def function():
    ...

async def function():
    ...

可互换使用。

两者在功能上有什么区别吗?

python python-3.x async-await python-3.5 python-asyncio
4个回答
69
投票

是的,使用

async def
语法的本机协程和使用
asyncio.coroutine
装饰器的基于生成器的协程之间存在功能差异。

根据PEP 492,介绍了

async def
语法:

  1. 原生协程对象不实现

    __iter__
    并且
    __next__
    方法。因此,它们不能被迭代或传递 到
    iter()
    list()
    tuple()
    和其他内置组件。他们也 不能在
    for..in
    循环中使用。

    尝试在本机协程上使用

    __iter__
    __next__
    对象将导致 TypeError 。

  2. 普通生成器不能

    yield from
    原生协程:这样做 将导致 TypeError 。

  3. 基于生成器的协程(对于异步代码,必须用

    @asyncio.coroutine
    )可以
    yield from
    原生协程对象

  4. inspect.isgenerator()
    inspect.isgeneratorfunction()
    返回
    False
    本机协程对象和本机协程函数

上面的第 1 点意味着,虽然使用

@asyncio.coroutine
装饰器语法定义的协程函数可以充当传统的生成器函数,但使用
async def
语法定义的协程函数却不能。

这是使用两种语法定义的两个最小的、表面上等效的协程函数:

import asyncio

@asyncio.coroutine
def decorated(x):
    yield from x 

async def native(x):
    await x 

尽管这两个函数的字节码几乎相同:

>>> import dis
>>> dis.dis(decorated)
  5           0 LOAD_FAST                0 (x)
              3 GET_YIELD_FROM_ITER
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 POP_TOP
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE
>>> dis.dis(native)
  8           0 LOAD_FAST                0 (x)
              3 GET_AWAITABLE
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 POP_TOP
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE

...唯一的区别是

GET_YIELD_FROM_ITER
GET_AWAITABLE
,当尝试迭代它们返回的对象时,它们的行为完全不同:

>>> list(decorated('foo'))
['f', 'o', 'o']

>>> list(native('foo'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'coroutine' object is not iterable

显然

'foo'
不是可等待的,因此尝试用它调用
native()
没有多大意义,但希望这一点很清楚:它返回的
coroutine
对象不是可迭代的,无论其参数如何。

Brett Cannon 对

async
/
await
语法的更详细研究:Python 3.5 中的 async/await 到底是如何工作的? 更深入地涵盖了这种差异。


22
投票

async def
是 Python 3.5 中的新语法。 您可以在
await
内使用
async with
async for
async def

@coroutine
async def
的功能类似物,但它适用于 Python 3.4+ 并使用
yield from
构造而不是
await

从实际角度来看,如果你的 Python 版本是 3.5+,请不要使用

@coroutine


3
投票

Python 3.5

coroutines
正式成为一种独特的类型,因此
async def
语法以及
await
语句。

在此之前,Python 3.4通过将常规函数包装到

generators
中来创建协程,因此使用了装饰器语法,以及更像生成器的
yield from


0
投票

在Python 3.4中,当原生协程不可用时,异步编程是使用

@asyncio.coroutine
实现的,它使用
yield from
语法来暂停和恢复生成器以执行异步任务。

但是,在Python 3.5中,引入了原生协程的概念,它使用

async def
来定义协程,可以使用
await
来暂停协程。这允许有效地暂停执行而不阻塞事件循环,从而提高性能。

因此,

async def
成为执行异步任务的新标准和首选方式。

这是一个简单的异步函数:

async def my_coroutine():
    await fetch_db_record()  # some asynchronous function
© www.soinside.com 2019 - 2024. All rights reserved.