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/