Threads e Automação em Paralelo em Python
Neste artigo, você vai aprender:
O que são threads.
Diferença entre paralelismo e concorrência.
Como usar o módulo
threading.Exemplo prático de automação em paralelo.
Cuidados e boas práticas no uso de threads.
🔹 1. O que são Threads?
Uma thread é uma unidade de execução dentro de um processo.
Um processo é um programa em execução (como o Python rodando um script).
Cada processo pode ter múltiplas threads, que compartilham memória e recursos.
Threads permitem que o programa faça várias coisas ao mesmo tempo, como:
✅ Baixar arquivos em paralelo.
✅ Ler dados enquanto processa outros.
✅ Realizar cálculos sem travar a interface gráfica.
🔹 2. Concorrência vs Paralelismo
Concorrência: quando várias tarefas parecem rodar ao mesmo tempo, mas na prática são alternadas rapidamente pelo sistema.
Paralelismo: quando múltiplas tarefas são realmente executadas ao mesmo tempo, em núcleos diferentes do processador.
👉 Em Python, devido ao GIL (Global Interpreter Lock), as threads não executam código Python puro em paralelo nos múltiplos núcleos. Mas elas são extremamente úteis para tarefas I/O-bound (entrada e saída), como:
Requisições de rede.
Leitura e escrita em arquivos.
Acesso a bancos de dados.
🔹 3. Usando o módulo threading
Python fornece o módulo threading, que facilita a criação e controle de threads.
Criando uma thread simples
import threading
import time
def tarefa(nome):
for i in range(3):
print(f"Executando {nome} - passo {i+1}")
time.sleep(1)
# Criando duas threads
t1 = threading.Thread(target=tarefa, args=("Thread 1",))
t2 = threading.Thread(target=tarefa, args=("Thread 2",))
# Iniciando as threads
t1.start()
t2.start()
# Esperando as threads terminarem
t1.join()
t2.join()
print("Execução finalizada!")
🔎 Saída esperada (ordem pode variar):
Executando Thread 1 - passo 1
Executando Thread 2 - passo 1
Executando Thread 1 - passo 2
Executando Thread 2 - passo 2
...
Execução finalizada!
🔹 4. Exemplo prático – Download de múltiplas páginas em paralelo
Imagine que você queira baixar o conteúdo de várias páginas da web ao mesmo tempo.
import threading
import requests
import time
urls = [
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/3",
"https://httpbin.org/delay/1"
]
def baixar(url):
print(f"Iniciando download: {url}")
resposta = requests.get(url)
print(f"Concluído: {url} - Status {resposta.status_code}")
threads = []
inicio = time.time()
# Criando uma thread para cada download
for url in urls:
t = threading.Thread(target=baixar, args=(url,))
threads.append(t)
t.start()
# Aguardando todas terminarem
for t in threads:
t.join()
fim = time.time()
print(f"Tempo total: {fim - inicio:.2f} segundos")
✅ Sem threads, cada download seria feito em sequência, levando 6 segundos ou mais.
✅ Com threads, as requisições são feitas em paralelo, reduzindo o tempo para aproximadamente 3 segundos.
🔹 5. Usando ThreadPoolExecutor (mais simples e moderno)
Em vez de gerenciar threads manualmente, podemos usar o concurrent.futures:
from concurrent.futures import ThreadPoolExecutor
import requests
urls = [
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/3",
"https://httpbin.org/delay/1"
]
def baixar(url):
print(f"Baixando {url}")
resposta = requests.get(url)
return f"{url} -> {resposta.status_code}"
with ThreadPoolExecutor(max_workers=3) as executor:
resultados = executor.map(baixar, urls)
for r in resultados:
print(r)
👉 O ThreadPoolExecutor facilita o uso de múltiplas threads, controlando o número de workers automaticamente.
🔹 6. Cuidados com Threads
⚠️ Compartilhamento de dados: como as threads compartilham memória, podem ocorrer condições de corrida.
✅ Use
threading.Lock()para proteger recursos críticos.
Exemplo:
import threading
contador = 0
lock = threading.Lock()
def incrementar():
global contador
for _ in range(100000):
with lock:
contador += 1
t1 = threading.Thread(target=incrementar)
t2 = threading.Thread(target=incrementar)
t1.start()
t2.start()
t1.join()
t2.join()
print("Contador:", contador)
Sem o lock, o valor final poderia ser incorreto.
🔹 7. Quando usar Threads?
✅ Útil para tarefas I/O-bound (rede, arquivos, banco de dados).
❌ Não é indicado para tarefas CPU-bound (cálculos pesados, criptografia, compressão) → nesse caso, use multiprocessing.
🔹 8. Conclusão
As threads em Python são uma ótima ferramenta para automação em paralelo quando o gargalo está em operações de entrada e saída. Elas:
Melhoram a performance de tarefas I/O-bound.
Permitem que várias operações rodem sem bloquear o programa.
São simples de implementar com
threadinge ainda mais fáceis comThreadPoolExecutor.
Se você precisa de paralelismo real em cálculos pesados, considere usar multiprocessing.

Comentários
Postar um comentário