Python の Async for ループ
このチュートリアルでは、Python の非同期 for
ループについて詳しく説明します。 非同期関数、非同期 for
ループ、および sleep
の概念について説明します。
次に、Python ライブラリ asyncio
と非同期コードを実行するために必要な関数について説明します。 最後に、概念を完全に理解するために、Python でいくつかの例を見ていきます。
Python の非同期関数
非同期関数は、同じプログラムの他の関数と並行して重いタスク (バッチ プログラムなど、バックグラウンドでプロセスを実行することに関心があるかもしれません) を実行するのに役立ちます。 関数が相互に依存していないか、相互に完全に依存していない場合、関数を並列に実行できます。
同期関数はタスクが完了すると制御を返しますが、非同期関数は制御を返し、他の関数/コードを並行して実行し、しばらくしてから制御を取り戻します。 このように、重いタスクを完了するだけでなく、他の多くのタスクも並行して完了します。
技術的には、同期関数は main
関数の制御をブロックしますが、非同期関数は main
関数をブロックせずに実行します。 このようにして、main
関数は複数の非同期関数を並行して実行できます。
Python の非同期 for
ループ
同期ループの場合、一時停止/制御を与えることなく実行されます。 ただし、それらを非同期にするには、非同期関数でそれらを定義する必要があります。 また、他の機能を制御するために、このプロセスで一定期間スリープする必要があります。
sleep
ステートメントを使用する
プロセス/スレッド/関数がしばらくスリープ状態になることがあります。 あなたはそれを休憩と考えるかもしれません。 ただし、その目的は、一定期間制御を失うことです。
その結果、他の関数が制御を取得します。 しばらくすると、制御が元に戻り、機能が再開されます。
いよいよ、Python での実装に移ります。 構文部分について順を追って説明し、最後に完全なコードを示します。
Python ライブラリと関数
asyncio
は、async/await
構文を使用して並行プログラム/関数を作成するための Python のライブラリです。 async
は、すべての関数の開始時に (非同期関数を作成するために) 使用されるキーワードです。
構文は次のとおりです。
async def fun_a(t):
ここで async
を追加して、この関数を非同期関数として宣言しています。
sleep
関数は、コルーチンの実行を一定期間中断することができます。 コルーチンは、実行中にパイプライン構造を作成するプロセス/関数です。
この関数は、await
キーワードを使用して、CPU を自発的に別の協調タスクに任せます。 sleep
関数の構文は次のとおりです。
await asyncio.sleep(1)
注意: キーワード
await
は、すべての非同期関数を呼び出すために必要です。これは、ライブラリまたはユーザー定義関数からのものです。
await
キーワードは、制御をイベント ループに戻します。 非同期関数が await
コマンドで呼び出された場合、sleep
ステートメント (for
ループ内) が、スリープ状態になるまで協調プロセスを制御すると考えることができます。
gather
関数は、複数の協調プロセス (技術的にはコルーチンを作成する) を組み合わせて、1つのユニットとして実行します。 この関数は、gather
呼び出しで記述された関数の順序で結果のタプルを返します。
構文は次のとおりです。
results = await asyncio.gather(fun_a(5), fun_b(5))
ここでは、fun_a
と fun_b
を同時に実行できるようにパイプラインを作成しています。
イベント ループは、すべての非同期アプリケーションの主要な構成要素です。 イベント ループは非同期関数を実行します。
get_event_loop()
メソッドは、set_event_loop
がまだ呼び出されていないかどうかを確認し、イベント ループを作成して現在のループとして設定します。 構文は次のとおりです。
my_loop = asyncio.get_event_loop()
ループがすでに作成されているときにこのコマンドを 2 回実行しても、何も実行されません。 ただし、最初の呼び出しではループは作成されません。 したがって、非同期ループが作成されます。
run_until_complete()
は、get_event_loop()
によって返されるループが非同期の場合、イベント ループを同時に実行するために使用されます。 構文は次のとおりです。
my_loop.run_until_complete(main())
main
関数が非同期の場合、このステートメントはコードを同時に実行します。
非同期コード
非同期関数/ルーチン/プロセスを実行するために必要な概念と Python ライブラリについて明確な考えを持っているので、完全なコーディング例を見てみましょう。
import asyncio
async def fun_a(t):
for i in range(t):
print("fun_a", end=" ")
await asyncio.sleep(1)
return 1
async def fun_b(t):
for i in range(t):
print("fun_b", end=" ")
await asyncio.sleep(1)
return 2
async def main():
results = await asyncio.gather(fun_a(5), fun_b(5))
print(results)
my_loop = asyncio.get_event_loop()
my_loop.run_until_complete(main())
このコードの一番上 (一番最初の行) で、asyncio
ライブラリをインポートしています。 このライブラリには、非同期関数を呼び出して同時に実行するために必要な関数があります。 それらはすでに構文で説明されています。
次に、同時に実行したい 2つの非同期関数 fun_a
と fun_b
があります。 ここでも、メイン関数から非同期関数を呼び出したいと考えています。 したがって、メインも非同期関数として作成されます。
また、5
を関数に渡して、その内部でループを 5 回実行していることにも注意してください。 そのため、後で出力を確認して、ループが完全に実行されていないことに気付くことができます。 それぞれがスリープ状態になり、他の機能に制御を渡します。
出力後にこの点を繰り返します。
main
関数内で gather
関数を呼び出し、非同期関数を渡して並列実行できるようにしました。 gather
関数は、ターゲットの非同期関数から返された 2つの値を持つタプルを返します。
いよいよ最後の2行に突入です。 最後から 2 行目で、get_event_loop
関数を呼び出してループを作成しました。 最後の行では、ループを使用して、run_until_complete
関数を呼び出して、main
関数の非同期実行を開始しました。
このコードの出力は次のとおりです。
fun_a fun_b fun_a fun_b fun_a fun_b fun_a fun_b fun_a fun_b [1, 2]
まず、ループが従来のコードのように完全に実行されていないことに注意してください。 代わりに、両方のループが同時に実行されます。 両方の関数 print
ステートメントの結果を確認できます。
最後に、[1, 2]
は非同期関数から main
関数が受け取ったタプルです。 1
と 2
は非同期関数によって返され、gather
関数でこれらの関数を記述した順序で配置されます。