@ asyncio.coroutine vs async def

时间:2016-11-13 08:05:34

标签: python python-3.x async-await python-3.5 python-asyncio

使用我见过的asyncio库,

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

async def function():
    ...

可互换使用。

两者之间是否有任何功能差异?

3 个答案:

答案 0 :(得分:42)

是的,使用async def语法的本地协同程序与使用asyncio.coroutine装饰器的基于生成器的协同程序之间存在功能差异。

根据PEP 492引入async def语法:

  
      
  1. 原生协程对象未实现__iter__和   __next__方法。因此,它们不能被迭代或传递   到iter()list()tuple()和其他内置插件。他们也   不能在for..in循环中使用。

         

    尝试在原生协程上使用__iter____next__   对象将导致TypeError。

  2.   
  3. 普通生成器不能yield from 原生协程:这样做   将导致TypeError。

  4.   
  5. 基于生成器的协同程序(对于asyncio代码必须使用   @asyncio.coroutine)可以yield from 原生协程对象

  6.   
  7. inspect.isgenerator()inspect.isgeneratorfunction()原生协程对象和原生协程函数返回False

  8.   

上面的第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 vs 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反对它无论其参数如何,return都不可迭代。

Brett Cannon对async / await语法的更详细调查:How the heck does async/await work in Python 3.5?更深入地涵盖了这种差异。

答案 1 :(得分:14)

async def是Python 3.5的新语法。 您可以在await内使用async withasync forasync def

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

对于实际观点,如果您的Python是3.5 +,则永远不要使用@coroutine

答案 2 :(得分:3)

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

在此之前, Python 3.4 通过将常规函数包装到generators中来创建协同程序,因此装饰器语法和类似生成器的yield from