concurrent.futures
concurrent.futures fornece pools de Executor de alto nível com objetos Future para resultados assíncronos. ThreadPoolExecutor sobrepõe I/O; ProcessPoolExecutor paraleliza trabalho de CPU.
Receita
from concurrent.futures import ThreadPoolExecutor, as_completed
def task(n: int) -> int:
return n + 1
with ThreadPoolExecutor(max_workers=4) as ex:
futures = [ex.submit(task, i) for i in range(10)]
for fut in as_completed(futures):
print(fut.result())Quando usar isso:
- Chamadas de bloqueio fan-out (HTTP, DB, arquivos)
- Pools de CPU sem gerenciamento manual de Processos
mapcom timeout e chunking- Cancelamento de grupos de trabalho no shutdown
- Integração com
asyncio.wrap_future
Exemplo Funcional
import time
from concurrent.futures import ProcessPoolExecutor, wait, FIRST_COMPLETED
def slow_square(n: int) -> int:
time.sleep(0.05)
return n * n
if __name__ == "__main__":
with ProcessPoolExecutor(max_workers=2) as ex:
futures = [ex.submit(slow_square, i) for i in range(6)]
done, not_done = wait(futures, return_when=FIRST_COMPLETED)
print("primeiro", done.pop().result())
for fut in not_done:
fut.cancel()O que isso demonstra:
waitcomFIRST_COMPLETEDpara resultados parciaiscancelcom melhor esforço em tarefas ainda não iniciadas- Pool de processos precisa de guarda principal e alvos serializáveis (picklable)
- Gerenciador de contexto espera por tarefas em execução na saída (a menos que canceladas)
Mergulho Profundo
Superfície da API
| Chamada | Comportamento |
|---|---|
submit(fn, *args) | Future único |
map(fn, iterable) | Iterador ordenado como a entrada |
as_completed(futures) | Gera à medida que cada um termina |
future.result(timeout=) | Bloqueia ou levanta TimeoutError |
Armadilhas
result()bloqueante sem timeout - trava o shutdown. Correção: timeouts + política de cancelamento.- Exceção no worker - armazenada no Future, levantada em
result(). Correção: tratar ou registrar por future. - Tarefas minúsculas no pool de processos - o custo de spawn domina. Correção: agrupar itens de trabalho.
- Executor global compartilhado - complica testes e ciclo de vida. Correção: injetar executor, fechar no shutdown da aplicação.
- Pool de threads para CPU - GIL limita o ganho de velocidade. Correção: ProcessPoolExecutor.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| asyncio.gather | I/O assíncrono nativo | SDK bloqueante |
| multiprocessing.Pool | Código legado | Greenfield prefere futures |
| joblib / dask | Paralelismo de big data | Scripts simples |
FAQs
Pool de Threads vs Processos?
Threads para bloqueio de I/O; processos para funções Python limitadas por CPU.
map vs submit?
map preserva a ordem e agrupa; submit oferece controle granular por tarefa.
Como as exceções se propagam?
Levantadas ao chamar result() no Future falho.
shutdown wait=False?
Retorna imediatamente; tarefas em execução continuam em segundo plano - usar com cuidado na saída.
integração com asyncio?
asyncio.wrap_future faz a ponte para awaitable em código misto.
default de max_workers?
min(32, cpu_count + 4) para threads - ajustar por carga de trabalho.
Posso usar initializer?
Sim, em ambos os tipos de executor para configuração por worker (conexões de DB - cuidado com segurança de processos).
Callbacks são thread-safe?
add_done_callback executa em thread arbitrária - mantenha callbacks curtos.
Como testar?
Injete um executor com max_workers=1 para determinismo em testes unitários.
GIL e ProcessPoolExecutor?
Cada processo tem seu próprio GIL - execução paralela real de bytecode.
Relacionado
- threading - primitivas por baixo dos panos
- multiprocessing - processos de baixo nível
- Sync/Async Bridging - executor padrão
- Choosing a Concurrency Model - escolha do tipo de pool
Versões da Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.