Einen Worker-Pool zu erstellen liefert dem Aufrufer nicht die heruntergeladenen Seiten. Behalte und verbrauche die Werte, die die übergebene Arbeit zurückgibt:

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()

Dieser Ausschnitt setzt eine begrenzte Liste von URLs und übliche Antwortgrößen voraus. Für erlaubte Prüfungen öffentlicher URLs ohne Proxy-Authentifizierung kann ein Kandidat aus der HTTP-Proxy-Liste den Beispiel-HTTP-Endpunkt des Managers ersetzen. Jedes Ergebnis enthält seine URL, damit der Aufrufer Status und Body der richtigen Anfrage zuordnen kann. map liefert Ergebnisse in Eingabereihenfolge; eine Ausnahme in einem Worker wird ausgelöst, wenn dieses Ergebnis abgerufen wird.

Der konfigurierte ProxyManager besitzt das Verbindungspooling für die Anfragen. Mit dem hier verwendeten Standardmodus für vorab geladene Antworten liest urllib3 den Body und gibt die Verbindung an seinen Pool zurück. Eine Streaming-Version bräuchte einen expliziten Verbrauch und eine Freigabe der Verbindung.

maxsize steuert normalerweise zurückgehaltene wiederverwendbare Verbindungen, keine harte Obergrenze für jeden geöffneten Socket. block=True ändert das relevante Poolverhalten, sodass Aufrufer auf eine freie Verbindung warten, statt zusätzliche über das Limit dieses Pools hinaus zu öffnen.

Die Worker-Anzahl begrenzt in diesem Beispiel die gleichzeitigen Aufrufe. Bei vielen Zielen zählen auch das Pool-Layout und die für HTTPS-Tunnel verwendete Route; eine Einstellung pro Pool sollte nicht als ein globales Socket-Kontingent für jeden Host beschrieben werden.

Ähnliche Artikel