使用我见过的asyncio库,
asyncio
@asyncio.coroutine def function(): ...
字符串和
async def function(): ...
型互换使用两者在功能上有什么区别吗?
z0qdvdin1#
是的,使用async def语法的原生协程和使用asyncio.coroutine装饰器的基于生成器的协程之间存在功能差异。根据PEP 492,它引入了async def语法:1.* 本机协程 * 对象不实现__iter__和__next__方法。因此,它们不能迭代或传递给iter(),list(),tuple()和其他内置程序。它们也不能在for..in循环中使用。尝试在本机协程对象上使用__iter__或__next__将导致TypeError。1.* 普通生成器 * 不能yield from * 原生协程 :这样做会导致TypeError。1. 基于生成器的协程 *(对于Pencio代码必须用@asyncio.coroutine修饰)可以yield from * 原生协程对象 *。
async def
asyncio.coroutine
__iter__
__next__
iter()
list()
tuple()
for..in
yield from
@asyncio.coroutine
inspect.isgenerator()
inspect.isgeneratorfunction()
False
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,当试图覆盖它们返回的对象时,它们的行为完全不同:
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语法进行了更详细的研究:How the heck does async/await work in Python 3.5?更深入地介绍了这种差异。
'foo'
native()
coroutine
async
await
cwtwac6a2#
async def是Python 3.5中的新语法。您可以在async def s中使用await,async with和async for。@coroutine是async def的函数类似物,但它在Python 3.4+中工作,并使用yield from构造而不是await。实际上,如果你的Python是3.5+,就不要使用@coroutine。
async with
async for
@coroutine
hi3rlvi23#
从 Python 3.5开始,coroutines正式成为一种独特的类型,因此async def语法,沿着出现await语句。在此之前,Python 3.4 通过将常规函数 Package 到generators中来创建协程,因此使用了装饰器语法,以及更像生成器的yield from。
coroutines
generators
ljsrvy3e4#
在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
字符串
4条答案
按热度按时间z0qdvdin1#
是的,使用
async def
语法的原生协程和使用asyncio.coroutine
装饰器的基于生成器的协程之间存在功能差异。根据PEP 492,它引入了
async def
语法:1.* 本机协程 * 对象不实现
__iter__
和__next__
方法。因此,它们不能迭代或传递给iter()
,list()
,tuple()
和其他内置程序。它们也不能在for..in
循环中使用。尝试在本机协程对象上使用
__iter__
或__next__
将导致TypeError。1.* 普通生成器 * 不能
yield from
* 原生协程 :这样做会导致TypeError。1. 基于生成器的协程 *(对于Pencio代码必须用
@asyncio.coroutine
修饰)可以yield from
* 原生协程对象 *。inspect.isgenerator()
和inspect.isgeneratorfunction()
为 native coroutine 对象和 *native coroutine函数 * 返回False
。上面的第1点意味着,虽然使用
@asyncio.coroutine
装饰器语法定义的协程函数可以像传统的生成器函数一样工作,但使用async def
语法定义的协程函数却不能。下面是两个最小的、表面上等价的协程函数,它们是用两种语法定义的:
字符串
虽然这两个函数的字节码几乎相同:
型
.唯一的区别是
GET_YIELD_FROM_ITER
与GET_AWAITABLE
,当试图覆盖它们返回的对象时,它们的行为完全不同:型
型
显然,
'foo'
不是一个可等待的对象,所以尝试用它来调用native()
没有多大意义,但重点是希望它返回的coroutine
对象是不可迭代的,不管它的参数是什么。Brett Cannon对
async
/await
语法进行了更详细的研究:How the heck does async/await work in Python 3.5?更深入地介绍了这种差异。cwtwac6a2#
async def
是Python 3.5中的新语法。您可以在async def
s中使用await
,async with
和async for
。@coroutine
是async def
的函数类似物,但它在Python 3.4+中工作,并使用yield from
构造而不是await
。实际上,如果你的Python是3.5+,就不要使用
@coroutine
。hi3rlvi23#
从 Python 3.5开始,
coroutines
正式成为一种独特的类型,因此async def
语法,沿着出现await
语句。在此之前,Python 3.4 通过将常规函数 Package 到
generators
中来创建协程,因此使用了装饰器语法,以及更像生成器的yield from
。ljsrvy3e4#
在Python 3.4中,当原生协程不可用时,异步编程是使用
@asyncio.coroutine
实现的,它使用yield from
语法来暂停和恢复生成器以执行异步任务。然而,在Python 3.5中,引入了原生协程的概念,它使用
async def
来定义协程,可以使用await
暂停协程。这允许在不阻塞事件循环的情况下有效地暂停执行,从而提高性能。因此,
async def
成为执行异步任务的新标准和首选方式。下面是一个简单的异步函数:
字符串