async/await: ノンブロッキングI/O

I/O待ち時間を有効活用。高並行処理の実現。

async
非同期関数を定義。
await
非同期処理の完了を待つ。
gather
複数の非同期処理を並列実行。

async/await

レストランの厨房 (Restaurant Kitchen)

非同期処理は「レストランの厨房」です。優秀なシェフ(CPU)は、オーブンで肉を焼いている間(I/O待ち時間)、ただぼーっと待ったりしません。その間に野菜を切ったり、皿を並べたりします(他のタスクを実行)。焼き上がったら(await完了)、また肉の調理に戻ります。これなら1人のシェフでも効率よく何品も作れます。

Pythonの `async/await` は、通信やデータベース操作などの「待ち時間」が発生する処理に最適です。待ち時間の間に他の処理を進めることで、プログラム全体の処理速度(特に同時接続数など)を劇的に向上させます。

Basic asyncio
import asyncio
async def fetch_data(url: str) -> str:
print(f"Fetching {url}...")
await asyncio.sleep(1) # 非同期待機
return f"Data from {url}"
async def main():
# 直列実行
result1 = await fetch_data("/api/users")
result2 = await fetch_data("/api/posts")
# 並列実行
results = await asyncio.gather(
fetch_data("/api/a"),
fetch_data("/api/b"),
fetch_data("/api/c"),
)
asyncio.run(main())
Bad
# ❌ Bad: 同期でブロック
import requests
def fetch_all():
r1 = requests.get(url1) # ブロック
r2 = requests.get(url2) # ブロック
return r1, r2
Good
# ✅ Good: 非同期で並列
import aiohttp
import asyncio
async def fetch_all():
async with aiohttp.ClientSession() as session:
r1, r2 = await asyncio.gather(
session.get(url1),
session.get(url2)
)
return r1, r2

パターン

Async Patterns
# タスクの作成
async def main():
task = asyncio.create_task(fetch_data())
# 他の処理...
result = await task
# タイムアウト
async def with_timeout():
try:
result = await asyncio.wait_for(
slow_operation(), timeout=5.0
)
except asyncio.TimeoutError:
print("Timed out!")
# 非同期イテレータ
async def read_stream():
async for line in async_reader:
process(line)
Tip: CPU バウンドは multiprocessing、I/O バウンドは asyncio。

合格ライン

asyncio.run と gather を使える
I/Oバウンドとの違いを説明できる

演習課題

課題1: async/await
async 関数を作成し await で呼び出してください。
課題2: asyncio.gather
複数の非同期タスクを並列実行してください。