Quando più thread condividono un piccolo pool di proxy, scegliere una voce a caso può assegnare lo stesso proxy a due operazioni attive. Una coda può contenere le voci attualmente disponibili per il prestito:

from contextlib import contextmanager
from queue import Queue

available = Queue()
for endpoint in dict.fromkeys(proxy_urls):
    available.put(endpoint)

@contextmanager
def borrow_proxy():
    endpoint = available.get(timeout=5)
    try:
        yield endpoint
    finally:
        available.put(endpoint)

def process_url(url):
    with borrow_proxy() as endpoint:
        return fetch_one(url, endpoint)

Costruite la coda una volta, prima di avviare i thread di lavoro. proxy_urls contiene URL di endpoint completi. I candidati pubblici sono disponibili nella lista di proxy gratuiti; usate il protocollo e il formato URL supportati da fetch_one. La funzione fetch_one sincrona esistente deve completare la sua operazione di rete e chiudere ogni risposta prima di tornare. Altrimenti il prestito finirebbe mentre la connessione usa ancora quel proxy.

Queue.get rimuove atomicamente una voce disponibile. Un pool esaurito attende invece di scansionare ripetutamente flag condivisi. Se nessuna voce arriva entro cinque secondi, queue.Empty raggiunge il chiamante; scegliete la politica di nuovo tentativo, errore o annullamento dell'applicazione per quel risultato.

Il blocco finally restituisce una voce acquisita dopo un successo o un'eccezione. Non dichiara che un endpoint fallito sia sano. Le politiche di quarantena, sostituzione e raffreddamento richiedono un percorso esplicito invece di scartare silenziosamente ogni proxy che incontra un errore temporaneo.

La deduplicazione delle stringhe URL identiche evita voci duplicate nella coda. URL distinti possono comunque riferirsi allo stesso proxy fisico o alla stessa uscita; raggruppateli deliberatamente se l'esclusività deve valere per quella risorsa condivisa. La coda coordina i thread di questo processo, non i worker su altre macchine.

Articoli correlati