@ asyncio.coroutine与异步def [英] @asyncio.coroutine vs async def

查看:68
本文介绍了@ asyncio.coroutine与异步def的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有了我见过的asyncio库,

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

async def function():
    ...

可互换使用.

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

Is there any functional difference between the two?

推荐答案

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

Yes, there are functional differences between native coroutines using async def syntax and generator-based coroutines using the asyncio.coroutine decorator.

根据 PEP 492 ,其中介绍了async def语法:

According to PEP 492, which introduces the async def syntax:

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

  1. Native coroutine objects do not implement __iter__ and __next__ methods. Therefore, they cannot be iterated over or passed to iter(), list(), tuple() and other built-ins. They also cannot be used in a for..in loop.

尝试在本机协程上使用__iter____next__ 对象将导致TypeError.

An attempt to use __iter__ or __next__ on a native coroutine object will result in a TypeError .

普通生成器无法yield from 本地协程: 会导致TypeError.

Plain generators cannot yield from native coroutines: doing so will result in a TypeError .

基于发电机的协程(因为异步代码必须用 @asyncio.coroutine)可以yield from 原生协程对象.

generator-based coroutines (for asyncio code must be decorated with @asyncio.coroutine) can yield from native coroutine objects.

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

上面的

第1点意味着,虽然使用@asyncio.coroutine装饰器语法定义的协程函数可以像传统的生成器函数那样工作,但使用async def语法定义的协程函数不能.

Point 1 above means that while coroutine functions defined using the @asyncio.coroutine decorator syntax can behave as traditional generator functions, those defined with the async def syntax cannot.

以下是用两种语法定义的两个最小的,表面上等效的协程函数:

Here are two minimal, ostensibly equivalent coroutine functions defined with the two syntaxes:

import asyncio

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

async def native(x):
    await x 

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

Although the bytecode for these two functions is almost identical:

>>> 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_ITERGET_AWAITABLE,当尝试遍历返回的对象时,它们的行为完全不同:

... the only difference being GET_YIELD_FROM_ITER vs GET_AWAITABLE, they behave completely differently when an attempt is made to iterate over the objects they return:

>>> 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对象是不可迭代的,无论其如何论点.

Obviously 'foo' is not an awaitable, so the attempt to call native() with it doesn't make much sense, but the point is hopefully clear that the coroutine object it returns is not iterable, regardless of its argument.

布雷特·坎农(Brett Cannon)对async/await语法的更详细研究:

A more detailed investigation of the async/await syntax by Brett Cannon: How the heck does async/await work in Python 3.5? covers this difference in more depth.

这篇关于@ asyncio.coroutine与异步def的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆