導入
非同期処理は、現代のアプリケーションにおいてパフォーマンスを向上させるための重要な技術です。特に、I/O待機が多いタスクやネットワーク通信を行う場合にその効果を発揮します。この記事では、Pythonを用いた非同期処理の具体的なシチュエーションを紹介し、その実装方法を学びます。
教科書レベルの解説(非同期処理)
重要な概念の整理
非同期処理は、主にイベントループとコルーチンを中心に構成されます。イベントループはタスクの実行を管理し、コルーチンは非同期的に実行される関数です。これにより、他の処理をブロックすることなく、同時に複数のタスクを進行させることが可能になります。
コード例(Python)
import asyncio
import aiohttp
async def fetch_data(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def main(urls):
tasks = [fetch_data(url) for url in urls]
results = await asyncio.gather(*tasks)
return results
urls = ['https://api.example.com/data1', 'https://api.example.com/data2']
data = asyncio.run(main(urls))
print(data)
コードの行ごとの解説
- import asyncio: asyncioモジュールをインポートします。
- import aiohttp: 非同期HTTPリクエストを行うためにaiohttpをインポートします。
- async def fetch_data(url):: 指定したURLからデータを非同期に取得する関数を定義します。
- async with aiohttp.ClientSession() as session:: aiohttpを使用してHTTPセッションを開始します。
- async with session.get(url) as response:: 非同期にGETリクエストを行い、レスポンスを取得します。
- return await response.json():: レスポンスをJSON形式で返します。
- async def main(urls):: 複数のURLを受け取り、非同期にデータを取得するメイン関数を定義します。
- tasks = [fetch_data(url) for url in urls]:: 各URLに対してfetch_data関数を呼び出すタスクを作成します。
- results = await asyncio.gather(*tasks):: 全てのタスクを並行して実行し、結果を取得します。
- data = asyncio.run(main(urls)):: main関数を実行し、データを取得します。
- print(data):: 取得したデータを出力します。
練習問題編
以下の練習問題に取り組んでみましょう。各問題には模範解答と解説が付いています。
- 問題1: 上記のコードにエラーハンドリングを追加し、HTTPリクエストが失敗した場合にエラーメッセージを表示するように修正せよ。
- 問題2: 非同期処理で取得したデータをCSV形式で保存する関数を実装せよ。
- 問題3: 同時に実行するタスクの数を制限する方法を説明し、その実装を示せ。
async def fetch_data(url):
try:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
response.raise_for_status()
return await response.json()
except Exception as e:
print(f"Error fetching {url}: {e}")
解説: raise_for_status()を使用して、HTTPエラーが発生した場合に例外を発生させます。これにより、エラーが発生したURLを特定しやすくなります。
import csv
async def save_to_csv(data, filename):
with open(filename, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerows(data)
解説: CSVファイルへの書き込みにはcsvモジュールを使用します。非同期処理の結果を受け取り、ファイルに保存します。
import asyncio
import aiohttp
async def limited_fetch_data(semaphore, url):
async with semaphore:
return await fetch_data(url)
async def main(urls, limit):
semaphore = asyncio.Semaphore(limit)
tasks = [limited_fetch_data(semaphore, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
解説: asyncio.Semaphoreを使用して、同時に実行するタスクの数を制限します。これにより、リソースの過剰使用を防ぎます。
まとめ
- 非同期処理は、I/O待機が多いタスクに特に効果的です。
- エラーハンドリングを適切に行うことで、堅牢なアプリケーションを構築できます。
- タスクの同時実行数を制限することで、システムリソースの管理が容易になります。