max_workers=8 limits executing threads. It does not stop a separate submission loop from creating a Future for every endpoint in a huge input.

Python 3.14 adds a bounded read-ahead option:

from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=8) as executor:
    for result in executor.map(check_proxy, endpoints, buffersize=24):
        record_result(result)

check_proxy is the existing synchronous check with network deadlines and cleanup; record_result handles its returned observation. The values 8 and 24 are example budgets. The free proxy list supplies public candidates for endpoints; keep their protocol with each address so check_proxy can use the correct transport.

When the submission buffer fills, map pauses consuming the iterable until results are yielded. This also applies to generators.

Map still yields in input order: a slow early check can hold completed later results and delay further input. For completion-order processing, use an explicitly bounded set of futures replenished as they finish.

Handle expected network failures inside the check if the batch should continue yielding results. An unhandled exception is raised when that item is retrieved. ThreadPoolExecutor's chunksize does not provide this submission budget, and earlier Python versions lack buffersize.

Winndannde jowitiiɗe heen