Muitas vezes acabamos escrevendo código em Python que faz requisições remotas ou lê vários arquivos ou processa alguns dados. E em muitos desses casos eu vi programadores usando um loop for simples que leva uma eternidade para terminar a execução. Por exemplo:
import requests
from time import time
lista_de_url = [
"https://via.placeholder.com/400",
"https://via.placeholder.com/410",
"https://via.placeholder.com/420",
"https://via.placeholder.com/430",
"https://via.placeholder.com/440",
"https://via.placeholder.com/450",
"https://via.placeholder.com/460",
"https://via.placeholder.com/470",
"https://via.placeholder.com/480",
"https://via.placeholder.com/490",
"https://via.placeholder.com/500",
"https://via.placeholder.com/510",
"https://via.placeholder.com/520",
"https://via.placeholder.com/530",
]
def baixar_arquivo(url):
html = requests.get(url, stream=True)
return html.status_code
inicio= time()
for url in lista_de_url:
print(baixar_arquivo(url))
print(f'Tempo gasto: {time() - inicio}')
Saída —--------------------
Tempo gasto: 6.340632677078247
Este é um exemplo sensato e o código abrirá cada URL, aguardará o carregamento, imprimirá seu código de status e só então passará para a próxima URL. Esse tipo de código é um candidato muito bom para multi-threading.
Os sistemas modernos podem executar muitos threads e isso significa que você pode executar várias tarefas ao mesmo tempo com uma sobrecarga muito baixa. Por que não tentamos fazer uso disso para fazer o código acima processar esses URLs mais rápido?
Faremos uso do ThreadPoolExecutor da biblioteca concurrent.futures. É superfácil de usar. Deixe-me mostrar um pouco de código e, em seguida, explicar como ele funciona.
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import time
lista_de_url = [
"https://via.placeholder.com/400",
"https://via.placeholder.com/410",
"https://via.placeholder.com/420",
"https://via.placeholder.com/430",
"https://via.placeholder.com/440",
"https://via.placeholder.com/450",
"https://via.placeholder.com/460",
"https://via.placeholder.com/470",
"https://via.placeholder.com/480",
"https://via.placeholder.com/490",
"https://via.placeholder.com/500",
"https://via.placeholder.com/510",
"https://via.placeholder.com/520",
"https://via.placeholder.com/530",
]
def baixar_arquivo(url):
html = requests.get(url, stream=True)
return html.status_code
inicio= time()
processos = []
with ThreadPoolExecutor(max_workers=10) as executor:
for url in lista_de_url:
processos.append(executor.submit(baixar_arquivo, url))
for tarefa in as_completed(processos):
print(tarefa.result())
print(f'Tempo gasto: {time() - inicio}')
Saída —--------------------
Tempo gasto: 1.0057077407836914
Acabamos de acelerar nosso código por um fator de quase 9! E nós nem fizemos nada super envolvido. Os benefícios de desempenho teriam sido ainda maiores se houvesse mais URLs.
Então o que está acontecendo? Quando chamamos executor.submit, estamos adicionando uma nova tarefa ao pool de threads. Armazenamos essa tarefa na lista de processos. Mais tarde, iteramos os processos e imprimimos o resultado.
O método as_completed produz os itens (tarefas) da lista de processos assim que eles são concluídos. Há dois motivos pelos quais uma tarefa pode ir para o estado concluído. Ele terminou de executar ou foi cancelado. Também poderíamos ter passado um parâmetro de tempo limite para as_completed e se uma tarefa demorasse mais que esse período de tempo, mesmo assim as_completed produziria essa tarefa.
Você deve explorar o multi-threading um pouco mais. Para projetos triviais, é a maneira mais rápida de acelerar seu código. Se você quiser aprender mais, leia os documentos oficiais. Eles são super úteis.
Este post foi retirado do link abiaxo:
link : https://yasoob.me/2019/05/29/speeding-up-python-code-using-multithreading/
0 Comentários