Pythonの 非同期処理ライブラリ asyncio の使い方
Pythonの 非同期処理ライブラリ「asyncio」の使い方をまとめました。
1. asyncio
「asyncio」は、Pythonの非同期処理ライブラリです。
2. 同期処理 と 非同期処理
「同期処理」では、タスクは順番に実行され、1つのタスクが完了するまで次のタスクは待たされます。これは直感的ですが、リソースを無駄にする可能性があります。たとえば、「ファイルアクセス」や「通信処理」のレスポンスを待つ間、他のタスクを実行できません。
一方、「非同期処理」は、時間のかかるタスクを実行している間に、他のタスクを実行することができます。これにより、効率的にリソースを利用し、アプリケーションの応答性を向上させることができます。
3. Colabで必要な前処理
Colabでは「asyncio」をインポートする前に、以下の処理が必要です。
# Colabで必要な前処理
import nest_asyncio
nest_asyncio.apply()
「asyncio」はデフォルトでイベントループのネストを許可していませんが、Colabはすでにイベントループが開始済みのため、これなしに「asyncio」を使用すると、次のようなエラーが表示されます。
RuntimeError: asyncio.run() cannot be called from a running event loop
4. コルーチンの実行
「コルーチン」は「async」で定義する「非同期関数」です。「await」で他の「非同期関数」を呼び出すことができ、その結果が返えるまで実行を一時停止します。コルーチン自体はただの定義で、「イベントループ」によって実行する必要があります。
4-1. コルーチンの実行
「コルーチン」の実行例は、次のとおりです。
import asyncio
async def main(): # mainコルーチンの定義
print('hello')
await asyncio.sleep(1) # 1秒スリープのコルーチン
print('world')
asyncio.run(main()) # mainコルーチンの実行
「hello」と表示された1秒後に「world」が表示されます。
hello
world
asyncio.run() でイベントループからコルーチンを実行しています。asyncio.sleep()は、任意の秒数スリープするコルーチンになります。
4-2. コルーチンの直列実行
「コルーチン」の直列実行の例は、次のとおりです。
say_after()を順番に「await」で呼び出しています。
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
say_after(1, 'hello')に1秒、say_after(2, 'world')に2秒、合計3秒かかりました。
started at 04:16:32
hello
world
finished at 04:16:35
5. タスクの実行
「タスク」は、コルーチンの実行状態(実行中、完了、キャンセルなど)を管理するためのオブジェクトです。asyncio.create_task() でコルーチンからタスクを作成することができます。コルーチンは直接キャンセルできませんが、タスク経由でキャンセルできます。
5-1. タスクの並列実行
「タスク」の並列実行の例は、次のとおりです。
async def main():
task1 = asyncio.create_task(
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
say_after(1, 'hello')に1秒、say_after(2, 'world')に2秒、並列実行のため2秒で完了します。
started at 04:32:03
hello
world
finished at 04:32:05
5-2. asyncio.gather()によるタスクの並列実行
asyncio.gather()にコルーチンを渡すことでも、タスクを並列実行することができます。自動的にタスクとしてスケジュールされます。コードを簡潔にかけますが、タスクのキャンセルなどはできません。
asyncio.gather()によるタスクの並列実行の例は、次のとおりです。
async def main():
print(f"started at {time.strftime('%X')}")
await asyncio.gather(
say_after(1, 'hello'),
say_after(2, 'world'),
)
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
say_after(1, 'hello')に1秒、say_after(2, 'world')に2秒、並列実行のため2秒で完了します。
started at 04:16:42
hello
world
finished at 04:16:44
この記事が気に入ったらサポートをしてみませんか?