並行する urllib3 プロキシリクエストから各結果を収集する
設定済みの ProxyManager をワーカースレッド間で共有し、エグゼキュータの結果イテレータを消費し、プールの保持と接続数の上限を区別します。
ワーカープールを作成しても、呼び出し元にダウンロード済みのページが渡されるわけではありません。送信した処理が返す値を保持して消費します:
from concurrent.futures import ThreadPoolExecutor
import urllib3
manager = urllib3.ProxyManager(
'http://proxy.example:8080',
maxsize=4,
block=True,
)
def fetch(url):
response = manager.request(
'GET', url, timeout=urllib3.Timeout(connect=5, read=15),
)
return url, response.status, response.data
try:
with ThreadPoolExecutor(max_workers=4) as workers:
results = list(workers.map(fetch, urls))
finally:
manager.clear()この断片は、限られた URL リストと通常のレスポンスサイズを前提としています。プロキシ認証なしで許可された公開 URL チェックには、HTTP プロキシリストの候補がマネージャのサンプル HTTP エンドポイントを置き換えられます。各結果には URL が含まれるため、呼び出し元はステータスと本文を正しいリクエストに関連付けられます。map は入力を順に結果を返します。ワーカー内の例外は、その結果を取り出すときに送出されます。
設定済みの ProxyManager がリクエストの接続プールを所有します。ここで使う既定のプリロード応答モードでは、urllib3 が本文を読み取り、接続をプールに戻します。ストリーミング版では明示的な消費と接続の解放が必要です。
maxsize は通常、保持される再利用可能な接続を制御するもので、開かれるすべてのソケットに対する厳格な上限ではありません。block=True は該当するプールの動作を変え、呼び出し元はそのプールの上限を超えて追加で開くのではなく、空き接続を待ちます。
この例ではワーカー数が同時呼び出しを制限します。宛先が多い場合、プールの構成と HTTPS トンネルに使う経路も重要です。1 つのプールの設定を、すべてのホストに対する単一のグローバルなソケット割当てとして説明すべきではありません。