ホームページ >バックエンド開発 >Python チュートリアル >高性能 Python: Asyncio
同時実行プログラミングは、複数のタスクの同時実行を扱うプログラミング アプローチです。 Python では、asyncio は非同期プログラミングを実装するための強力なツールです。コルーチンの概念に基づいて、asyncio は I/O 集中型のタスクを効率的に処理できます。この記事では、asyncio の基本原理と使用法を紹介します。
I/O 操作を処理する場合、マルチスレッドを使用すると、通常の単一スレッドと比較して効率が大幅に向上することがわかっています。では、なぜ依然として asyncio が必要なのでしょうか?
マルチスレッドには多くの利点があり、広く使用されていますが、次のような制限もあります。
asyncio はまさにこれらの問題を解決するために登場しました。
まず、Sync (同期) と Async (非同期) の概念を区別しましょう。
要約すると、asyncio の動作原理はコルーチンとイベント ループのメカニズムに基づいています。非同期操作にコルーチンを使用し、イベント ループにコルーチンのスケジューリングと実行を担当させることにより、asyncio は効率的な非同期プログラミング モデルを実現します。
コルーチンは、asyncio の重要な概念です。これらは、スレッド切り替えのオーバーヘッドなしでタスク間を素早く切り替えることができる軽量の実行ユニットです。コルーチンは async キーワードを使用して定義でき、await キーワードはコルーチンの実行を一時停止し、特定の操作が完了した後に再開するために使用されます。
これは、非同期プログラミングにコルーチンを使用する方法を示す簡単なサンプル コードです。
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
この例では、関数 hello() は async キーワードで定義されたコルーチンです。コルーチン内で await を使用して実行を一時停止できます。ここでは、時間のかかる操作をシミュレートするために asyncio.sleep(1) が使用されています。 run_until_complete() メソッドは、コルーチンをイベント ループに追加して実行します。
asyncio は主に、ネットワーク リクエスト、ファイルの読み取りと書き込みなど、I/O 集中型のタスクを処理するために使用されます。これは、非同期 I/O 操作用の一連の API を提供します。これを await キーワードと組み合わせて使用すると、非同期プログラミングを簡単に実現できます。
これは、非同期ネットワーク リクエストに asyncio を使用する方法を示す簡単なサンプル コードです。
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
この例では、ネットワークリクエストに aiohttp ライブラリを使用します。関数 fetch() はコルーチンです。 session.get() メソッドを通じて非同期 GET リクエストを開始し、await キーワードを使用して応答が返されるのを待ちます。関数 main() は別のコルーチンです。再利用のために内部に ClientSession オブジェクトを作成し、 fetch() メソッドを呼び出して Web ページのコンテンツを取得して印刷します。
注: ここでは、requests ライブラリの代わりに aiohttp を使用します。これは、aiohttp ライブラリには互換性があるのに対し、requests ライブラリには asyncio との互換性がないためです。 asyncio を有効に活用するには、特にその強力な機能を発揮するには、多くの場合、対応する Python ライブラリが必要です。
asyncio は、asyncio.gather() や asyncio.wait() など、複数のタスクを同時に実行するためのメカニズムも提供します。以下は、これらのメカニズムを使用して複数のコルーチン タスクを同時に実行する方法を示すサンプル コードです。
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
この例では、2 つのコルーチン タスク task1() と task2() を定義し、どちらも時間のかかる操作を実行します。コルーチン main() は、asyncio.gather() を通じてこれら 2 つのタスクを同時に開始し、それらが完了するのを待ちます。同時実行により、プログラムの実行効率が向上します。
実際のプロジェクトでは、マルチスレッドと非同期のどちらを選択すべきでしょうか?大物がそれを鮮やかに要約しました:
import asyncio async def hello(): print("Hello") await asyncio.sleep(1) # Simulate a time-consuming operation print("World") # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(hello())
リストを入力します。リスト内の各要素について、0 からこの要素までのすべての整数の二乗和を計算します。
import asyncio import aiohttp async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: html = await fetch(session, 'https://www.example.com') print(html) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
実行時間は計算に 16.00943413000002 秒かかります
import asyncio async def task1(): print("Task 1 started") await asyncio.sleep(1) print("Task 1 finished") async def task2(): print("Task 2 started") await asyncio.sleep(2) print("Task 2 finished") async def main(): await asyncio.gather(task1(), task2()) # Create an event loop loop = asyncio.get_event_loop() # Add the coroutine to the event loop and execute loop.run_until_complete(main())
実行時間は計算に 7.314132894999999 秒かかります
この改良されたコードでは、concurrent.futures.ProcessPoolExecutor を使用してプロセス プールを作成し、executor.map() メソッドを使用してタスクを送信して結果を取得します。 executor.map() を使用した後、結果を取得する必要がある場合は、結果をリストに反復処理するか、他のメソッドを使用して結果を処理できることに注意してください。
if io_bound: if io_slow: print('Use Asyncio') else: print('Use multi-threading') elif cpu_bound: print('Use multi-processing')
実行時間は計算に 5.024221667 秒かかります
concurrent.futures.ProcessPoolExecutor と multiprocessing はどちらも、Python でマルチプロセスの同時実行性を実装するためのライブラリです。いくつかの違いがあります:
要約すると、concurrent.futures.ProcessPoolExecutor は、基礎となるマルチプロセス関数をカプセル化する高レベルのインターフェイスであり、単純なマルチプロセス タスクの並列化に適しています。 multiprocessing はより低レベルのライブラリであり、より詳細な制御と柔軟性を提供し、プロセスのきめ細かい制御が必要なシナリオに適しています。特定の要件に応じて適切なライブラリを選択する必要があります。単純なタスクの並列化だけの場合は、concurrent.futures.ProcessPoolExecutor を使用してコードを簡素化できます。さらに低レベルの制御と通信が必要な場合は、マルチプロセッシング ライブラリを使用できます。
マルチスレッドとは異なり、asyncio はシングルスレッドですが、内部イベント ループのメカニズムにより、複数の異なるタスクを同時に実行でき、マルチスレッドよりも優れた自律制御が可能です。
asyncio のタスクは動作中に中断されないため、競合状態の状況は発生しません。
特に大量の I/O 操作を伴うシナリオでは、asyncio はマルチスレッドよりも操作効率が高くなります。 asyncio でのタスク切り替えのコストはスレッド切り替えのコストよりもはるかに小さく、asyncio が開始できるタスクの数はマルチスレッドのスレッド数よりもはるかに多いためです。
ただし、多くの場合、asyncio を使用するには、前の例の aiohttp など、特定のサードパーティ ライブラリのサポートが必要であることに注意してください。また、I/O 操作が高速で重くない場合は、マルチスレッドを使用すると問題を効果的に解決できます。
最後に、Flask/FastAPI をデプロイするための理想的なプラットフォームである Leapcell を紹介します。
Leapcell は、最新の分散アプリケーション向けに特別に設計されたクラウド コンピューティング プラットフォームです。従量課金制の料金モデルにより、アイドルコストは発生しません。つまり、ユーザーは実際に使用したリソースに対してのみ料金を支払います。
ドキュメントで詳細を確認してください!
Leapcell Twitter: https://x.com/LeapcellHQ
以上が高性能 Python: Asyncioの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。