web-dev-qa-db-ja.com

@ asyncio.coroutine vs async def

私が見たasyncioライブラリで、

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

そして

async def function():
    ...

交換可能に使用されます。

2つの間に機能的な違いはありますか?

37
Jason

はい、_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()は、native coroutineオブジェクトおよびnative coroutine functionsに対してFalseを返します。

上記のポイント1は、_@asyncio.coroutine_デコレーター構文を使用して定義されたコルーチン関数は従来のジェネレーター関数として動作できますが、_async def_構文で定義された関数は動作できないことを意味します。

2つの構文で定義された、表面上は同等の2つの最小限のコルーチン関数を以下に示します。

_import asyncio

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

async def native(x):
    await x 
_

これら2つの関数のバイトコードはほぼ同じですが、

_>>> 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_であり、返されるオブジェクトを反復しようとすると、まったく異なる動作をします。

_>>> 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構文のより詳細な調査: Python 3.5? で非同期/待機がどのように機能するかこの違いをより深くカバーしています。

43
Zero Piraeus

async defはPython 3.5。からの新しい構文です。awaitasync withおよびasync for内部async defs。

@coroutineasync defしかし、Python 3.4+で動作し、yield fromの代わりにawaitを作成します。

実用的な観点からは、@coroutine Pythonが3.5+の場合。

15
Andrew Svetlov

Python 3.5coroutinesが正式に特殊タイプになったため、async def構文とawaitステートメント。

それ以前は、Python 3.4は、通常の関数をgeneratorsにラップすることでコルーチンを作成しました。したがって、デコレーター構文、およびよりジェネレーターに似たyield from

3
songololo