"Python as_completed Example: Process Futures as They Finish"

"A complete python as_completed example: submit I/O work to a ThreadPoolExecutor, process futures in completion order, catch worker exceptions, and pick the right max_workers."

You submitted 200 jobs to a ThreadPoolExecutor with executor.map() — and then sat staring at a blank terminal, waiting for the *slowest* job before seeing a single result. That's the tax of ordered iteration: map() yields results in submission order, so one straggler holds the whole line hostage. This python as_completed example shows the fix: concurrent.futures.as_completed() hands you each future the moment its thread finishes, so you can log progress, stream output, and react to failures as they happen instead of at the end. Last updated: 2026-10-05 What you'll build and learn Submit callables to a ThreadPoolExecutor and get Future objects back Understand the executor.submit vs executor.map trade-off Iterate futures with as_completed() to process results in finish order Map each future back to its input with a future_to_x dict Use future.result() with a timeout and understand its exception re-raise rule Handle exceptions raised inside worker threads — per future, in the main thread Size max_workers correctly for I/O-bound work Decide between ThreadPoolExecutor , ProcessPoolExecutor , and asyncio.to_thread All code below was run on Python 3.12 . The semantics shown are unchanged in 3.13 and 3.14. executor.submit vs executor.map: why futures matter first executor.map(fn, items) is the convenient one: it returns results in the same order as the inputs. But that ordering is a leash — iteration blocks on each result *in order*, even if result #47 finished an hour ago and result #3 is still crawling. executor.submit(fn, *args) is the primitive: it returns a Future immediately, a handle on work that may not be done yet. With futures you choose how to collect: from concurrent.futures import ThreadPoolExecutor def square(n): return n * n with…

Explore