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语法:
原生协程对象没有实现
__iter__和__next__方法.因此,它们不能被遍历或传递给iter(),list(),tuple()和其他内置插件.它们也不能用于for..in循环中.尝试使用
__iter__或__next__在本机协程对象上将导致TypeError.普通生成器不能使用
yield from本机协程:这样做会导致TypeError.基于生成器的协同程序(用于asyncio代码必须装饰
@asyncio.coroutine)可以是yield from本机协同程序对象.
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中工作?更深入地涵盖了这种差异.
And*_*lov 15
async def是Python 3.5的新语法.你可以使用await,async with而async for里面async def秒.
@coroutine是一个功能模拟,async def但它适用于Python 3.4+并使用yield from构造而不是await.
@coroutine如果您的Python是3.5+,那么从实际角度来看就永远不会使用.