threading
O módulo threading executa threads do SO em um único processo com memória compartilhada. Use threads para sobreposição de I/O-bound; proteja estado mutável compartilhado com Lock, RLock, Event e Condition.
Receita
import threading
counter = 0
lock = threading.Lock()
def inc() -> None:
global counter
with lock:
counter += 1Quando usar:
- Bloqueio de I/O HTTP, DB, filesystem em paralelo
- Workers em segundo plano em um aplicativo síncrono
- Timers e tarefas periódicas (
threading.Timer) - Sinalização entre threads (
Event) - Ponte entre bibliotecas síncronas dentro de async via executor
Exemplo de Trabalho
import threading
import time
from queue import Queue
results: Queue[int] = Queue()
stop = threading.Event()
def worker(worker_id: int) -> None:
while not stop.is_set():
time.sleep(0.05)
results.put(worker_id)
threads = [threading.Thread(target=worker, args=(i,), daemon=True) for i in range(3)]
for t in threads:
t.start()
time.sleep(0.2)
stop.set()
for t in threads:
t.join(timeout=1)
print("collected", results.qsize())O que isso demonstra:
Eventsinaliza desligamento gracioso- Threads daemon saem quando a principal sai - use não-daemon para trabalho de flush
Queuepassa resultados sem bloqueio manual em listajoin(timeout)evita travamento no desligamento
Mergulho Profundo
Primitivas
| Tipo | Uso |
|---|---|
| Lock | Exclusão mútua |
| RLock | Lock reentrante na mesma thread |
| Event | Sinalizador de uso único ou persistente |
| Semaphore | Limita a contagem de concorrência |
Thread Safety
- Prefira mensagens imutáveis através de filas
- Proteja invariantes que abrangem múltiplas operações com locks
threading.local()para estado por thread- Deadlock: sempre adquira locks em ordem consistente
Armadilhas
- Mutações compartilhadas sem lock - corridas corrompem dados. Correção:
with lock:ou fila. - Deadlock com locks aninhados - A então B vs B então A. Correção: documentação de ordem de locks.
- Threads daemon no meio da escrita - saída truncada na saída. Correção: use
joinem workers não-daemon. - Threads CPU-bound para velocidade - GIL limita bytecode paralelo. Correção:
multiprocessing. - Muitas threads - thrash de troca de contexto. Correção: tamanho do pool ~ esperas de I/O concorrentes.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| asyncio | I/O de alto fan-out, APIs async | Apenas SDKs bloqueantes |
| multiprocessing | Paralelismo de CPU | Precisa de memória compartilhada |
| concurrent.futures | Abstração de pool | Ciclo de vida de thread customizado |
FAQs
Quantas threads?
Comece perto das operações de bloqueio concorrentes (conexões), não da contagem de núcleos de CPU.
Lock vs RLock?
RLock quando a mesma thread reentra em código protegido (helpers recursivos).
list.append é thread-safe?
Um único append é atômico em CPython, mas operações compostas de leitura-modificação-escrita não são.
threading vs _thread?
Use threading - nível mais alto, suporta locks e join.
Como threads interagem com asyncio?
loop.run_in_executor executa código bloqueante em um pool de threads sem bloquear o loop.
O que é armazenamento local de thread?
Atributos de threading.local() isolados por thread - útil para contexto de requisição em WSGI síncrono.
Posso compartilhar SQLite entre threads?
Use a mesma conexão por thread ou verifique o modo de thread safety do sqlite3 - geralmente acesso serial.
Como nomear threads?
Thread(name="worker-1") melhora a legibilidade do depurador e logs.
As threads do ThreadPoolExecutor são reutilizadas?
Sim - o pool amortiza o custo de criação de threads.
Como testar código de threading?
Testes de estresse + threading.Barrier; evite asserções de timing instáveis - use eventos.
Relacionados
- The GIL & Free-Threaded Python - Limites de CPU
- Queues & Producer/Consumer - Hand-off seguro
- concurrent.futures - Pools
- Sync/Async Bridging - Executors
Versões do 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+.