@ asyncio.coroutine vs async def

Jas*_*son 39 python python-3.x async-await python-asyncio python-3.5

有了asyncio我见过的图书馆,

@asyncio.coroutine
def function():
    ...
Run Code Online (Sandbox Code Playgroud)

async def function():
    ...
Run Code Online (Sandbox Code Playgroud)

可互换使用.

这两者之间有什么功能差异吗?

Zer*_*eus 46

是的,使用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代码必须装饰 @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 
Run Code Online (Sandbox Code Playgroud)

虽然这两个函数的字节码几乎相同:

>>> 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
Run Code Online (Sandbox Code Playgroud)

...唯一的区别是GET_YIELD_FROM_ITERvs GET_AWAITABLE,当尝试迭代它们返回的对象时,它们的行为完全不同:

>>> list(decorated('foo'))
['f', 'o', 'o']
Run Code Online (Sandbox Code Playgroud)

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

显然'foo'不是一个等待的,所以native()用它调用的尝试没有多大意义,但有希望清楚的是coroutine它返回的对象不是可迭代的,无论它的参数如何.

Brett Cannon 对async/ awaitsyntax的更详细的调查:异步/等待如何在Python 3.5中工作?更深入地涵盖了这种差异.

  • @roachsinai 它[不](https://docs.python.org/3/library/inspect.html#inspect.iscoroutinefunction)。 (2认同)

And*_*lov 15

async def是Python 3.5的新语法.你可以使用await,async withasync for里面async def秒.

@coroutine是一个功能模拟,async def但它适用于Python 3.4+并使用yield from构造而不是await.

@coroutine如果您的Python是3.5+,那么从实际角度来看就永远不会使用.