Pythonでgrequestsを使用した並列リクエストの送信

requestsライブラリはPythonでAPIリクエストを扱う際に非常に使いやすく、K氏が開発した非同期処理をサポートしていないため、逐次実行される。テスト効率を向上させるために並列処理が必要な場合、マルチスレッドやコルーチン、gevent、aiohttpなどの技術が利用可能だが、実装がやや複雑である。

grequestsはK氏がgeventとrequestsを組み合わせて開発した並列リクエスト送信ライブラリであり、簡単なインターフェースで利用できる。

インストール方法: pip install gevent grequests
プロジェクトURL: https://github.com/spyoungtech/grequests

grequestsの基本的な使用方法

まず、リクエストタスクのリストを作成し、grequests.map()メソッドを使用して並列処理を行う。

import grequests

request_tasks = [   # リクエストタスクリスト
    grequests.get('http://httpbin.org/get?a=1&b=2'),
    grequests.post('http://httpbin.org/post', data={'x':1,'y':2}),
    grequests.put('http://httpbin.org/post', json={'x': 1, 'y': 2}),
]

response_results = grequests.map(request_tasks)    # 並列実行後結果取得
print(response_results[0].text)  # 最初のリクエストの応答テキスト出力

grequestsはget、post、put、deleteなどのHTTPメソッドをサポートしており、パラメータの指定方法はrequestsと同様である。

requestsとのパフォーマンス比較

100回のGitHubへのリクエスト処理時間を比較する。

requestsによる逐次処理:

import requests
import time

start = time.time()
responses = [requests.get('https://github.com') for _ in range(100)]
print(time.time()-start)

grequestsによる並列処理:

import grequests
import time

start = time.time()
request_tasks = [grequests.get('https://github.com') for _ in range(100)]
response_results = grequests.map(request_tasks)
print(time.time()-start)

実測ではrequestsは約100秒、grequestsは約3.58秒で処理が完了した。

例外処理の実装

複数リクエスト送信時にURLが存在しない、タイムアウトなどエラーが発生する可能性があるため、カスタム例外処理を設定可能。

import grequests

def handle_exception(request, error):
    print("リクエスト失敗")

request_tasks = [
    grequests.get('http://httpbin.org/delay/1', timeout=0.001),   # タイムアウト
    grequests.get('http://invaliddomain/'),   # 存在しないドメイン
    grequests.get('http://httpbin.org/status/500')    # 500エラーを返すリクエスト
]

response_results = grequests.map(request_tasks, exception_handler=handle_exception)
print(response_results)

実行結果:

リクエスト失敗
リクエスト失敗
[None, None, <Response [500]>]

タグ: grequests gevent Python 並列処理 HTTPリクエスト

7月3日 18:44 投稿