web-dev-qa-db-ja.com

Python非同期理解-どのように機能しますか?

Python 3.6。で説明されている非同期内包表記の使用を理解するのに問題があります。免責事項として、Pythonで一般的に非同期コードを扱う経験はあまりありません。

Python 3.6 ドキュメントの新機能は次のとおりです。

_result = [i async for i in aiter() if i % 2]
_

[〜#〜] pep [〜#〜] では、これは次のように展開されます。

_result = []
async for i in aiter():
    if i % 2:
        result.append(i)
_

Ithinkaiter()関数が非同期に呼び出されるため、aiterの各反復が前のものは必然的にまだ戻っています(または、この理解は間違っていますか?)。

私がわからないのは、それがどのようにここでリストの理解に変換されるかということです。結果は返される順にリストに入れられますか?または、各結果が正しい順序でリストに配置されるように、最終リストに効果的な「プレースホルダー」がありますか?または、私はこれについて間違った方法で考えていますか?

さらに、誰かが、このような理解での適用可能なユースケースとasyncの基本的な仕組みの両方を示す実世界の例を提供できますか?

30
Andrew Guy

基本的に、通常のループで_async for_ループがどのように機能するかを尋ねています。リスト内包表記でこのようなループを使用できるようになったからといって、ここでは何の違いもありません。これは、通常のリスト内包表記とまったく同じように、繰り返しlist.append()呼び出しを避ける最適化です。

その後、_async for_ループは、通常のforループがブロックする反復プロトコルの次の各ステップを単に待機します。

説明のために、通常のforループを想像してください:

_for foo in bar:
    ...
_

このループでは、Pythonが本質的にこれを行います。

_bar_iter = iter(bar)
while True:
    try:
        foo = next(bar_iter)
    except StopIteration:
        break
    ...
_

next(bar_iter)呼び出しは非同期ではありません。ブロックします。

forを_async for_に置き換え、Pythonの変更点:

_bar_iter = aiter(bar)  # aiter doesn't exist, but see below
while True:
    try:
        foo = await anext(bar_iter)  # anext doesn't exist, but see below
    except StopIteration:
        break
    ...
_

上記の例では、aiter()anext()は架空の関数です。これらはiter()およびnext()の機能的に完全に同等ですが、___iter___および___next___の代わりに___aiter___および___anext___を使用します。つまり、同じ機能用の非同期フックが存在しますが、接頭辞aによって非同期フックとは区別されます。

awaitキーワードには重大な違いがあるため、反復ごとに_async for_ループが制御を生成するため、代わりに他のコルーチンを実行できます。

繰り返しになりますが、これはすべてPython 3.5で既に追加されています( PEP 492 を参照)。Python 3.6の新しい点は、リスト内包表記でもこのようなループを使用できます。また、ジェネレーター式およびセットおよびディクテーションの理解では、その点についてです。

最後になりましたが、同じ一連の変更により、内包表記の式セクションで_await <expression>_を使用できるようになりました。

_[await func(i) for i in someiterable]
_

今は可能です。

20
Martijn Pieters

I 思考aiter()関数が非同期に呼び出されることを理解しているため、aiterの各反復は、前の反復がまだ戻ることなく続行できます(または、この理解は違う?)。

その理解は間違っています。 async forループの反復は並行して実行できません。 async forは、通常のforループと同様にシーケンシャルです。

async forの非同期部分は、コルーチンの代わりにイテレータawaitを反復させることです。これは、非同期コルーチン内で使用するためのものであり、特別な非同期イテラブルでのみ使用するためのものです。それ以外は、ほとんどが通常のforループのようです。

11
user2357112