O threading reduz significativamente o tempo de execução de um programa. Aprenda como implementar threading em Python.

O tempo de execução é uma das medidas comuns da eficiência de um programa. Quanto mais rápido o tempo de execução, melhor o programa. Threading é uma técnica que permite que um programa execute várias tarefas ou processos simultaneamente.

Você aprenderá como usar o Python integrado rosqueamento módulo e o simultâneas.recursos módulo. Ambos os módulos oferecem maneiras simples de criar e gerenciar threads

Importância do Rosqueamento

O encadeamento reduz a quantidade de tempo que um programa leva para concluir um trabalho. Se o trabalho contiver várias tarefas independentes, você poderá usar o encadeamento para executar as tarefas simultaneamente, reduzindo o tempo de espera do programa para que uma tarefa seja concluída antes de passar para a próxima.

Por exemplo, um programa que baixa vários arquivos de imagem da Internet. Este programa pode utilizar threading para baixar os arquivos em paralelo, em vez de um de cada vez. Isso elimina o tempo que o programa teria que esperar para que o processo de download de um arquivo fosse concluído antes de passar para o próximo.

instagram viewer

Programa inicial antes de rosquear

A função no programa a seguir representa uma tarefa. A tarefa é pausar a execução do programa por um segundo. O programa chama a função duas vezes, criando assim duas tarefas. Em seguida, ele calcula o tempo que o programa inteiro levou para ser executado e o exibe na tela.

importar tempo

start_time = time.perf_counter()

defpausa():
imprimir('Dormir 1 segundo...')
hora de dormir(1)
imprimir('Terminei de Dormir...')

pausa()
pausa()
hora_final = hora.perf_counter()
imprimir(f'Concluído em {rodada (fim_hora - hora_início, 2)} segundo(s)')

A saída mostra que o programa levou 2,01 segundos para ser executado. Cada tarefa levou um segundo e o restante do código levou 0,01 segundo para ser executado.

Você pode usar threading para executar simultaneamente ambas as tarefas. Isso levará um segundo para ambas as tarefas serem executadas.

Implementando Threading Usando o Módulo Threading

Para modificar o código inicial para implementar o threading, importe o rosqueamento módulo. Crie dois tópicos, thread_1 e thread_2 usando o Fio aula. Ligar para começar método em cada thread para iniciar sua execução. Ligar para juntar método em cada thread para aguardar a conclusão de sua execução antes que o restante do programa seja executado.

importar tempo
importar rosqueamento
start_time = time.perf_counter()

defpausa():
imprimir('Dormir 1 segundo...')
hora de dormir(1)
imprimir('Terminei de Dormir...')

thread_1 = encadeamento. Tópico (alvo=pausa)
thread_2 = encadeamento. Tópico (alvo=pausa)

thread_1.start()
thread_2.start()

thread_1.join()
thread_2.join()

hora_final = hora.perf_counter()
imprimir(f'Concluído em {rodada (fim_hora - hora_início, 2)} segundo(s)')

O programa executará ambos os threads simultaneamente. Isso reduzirá o tempo necessário para realizar ambas as tarefas.

A saída mostra que o tempo necessário para executar as mesmas tarefas é de cerca de um segundo. Isso é metade do tempo que o programa inicial levou.

Implementando Threading Usando o Módulo concurrent.futures

Python 3.2 viu a introdução do concorrentes.futuros módulo. Este módulo fornece uma interface de alto nível para executar tarefas assíncronas usando threads. Ele fornece uma maneira mais simples de executar tarefas em paralelo.

Para modificar o programa inicial para usar encadeamento, importe o módulo concurrent.features. Use o ThreadPoolExecutor class do módulo concurrent.futures para criar um pool de threads. Envie o pausa função para a piscina duas vezes. O enviar método retorna um futuro objeto que representa o resultado da chamada da função.

Iterar sobre o futuros e imprima seus resultados usando o resultado método.

importar tempo
importar concorrentes.futuros

start_time = time.perf_counter()

defpausa():
imprimir('Dormir 1 segundo...')
hora de dormir(1)
retornar'Terminei de Dormir...'

com concorrentes.futuros. ThreadPoolExecutor() como executor:
resultados = [executor.submit (pausa) para _ em faixa(2)]
para f em concurrent.futures.as_completed (resultados):
imprimir (f.resultado())

hora_final = hora.perf_counter()

imprimir(f'Concluído em {rodada (fim_hora - hora_início, 2)} segundo(s)')

O módulo concurrent.features cuida de iniciar e juntar as threads para você. Isso torna seu código mais limpo.

A saída é idêntica à do módulo de rosqueamento. O módulo de encadeamento é útil para casos simples em que você precisa executar alguns encadeamentos em paralelo. Por outro lado, o módulo concurrent.futures é útil para casos mais complexos onde você precisa executar muitas tarefas simultaneamente.

Usando Threading em um Cenário do Mundo Real

O uso de threads para executar o programa acima reduziu o tempo em um segundo. No mundo real, os threads economizam mais tempo. Crie um programa que baixe imagens da internet. Começar por criando um novo ambiente virtual. Execute o seguinte comando no terminal para instalar o solicitações de biblioteca:

solicitações de instalação do pip

A biblioteca de solicitações permitirá que você envie solicitações HTTP. Importe a biblioteca de solicitações e a biblioteca de tempo.

importar solicitações de
importar tempo

Crie uma lista de URLs das imagens que você gostaria de baixar. Deixe-os ser pelo menos dez para que você possa notar uma diferença significativa ao implementar o encadeamento.

img_urls = [
' https://images.unsplash.com/photo-1524429656589-6633a470097c',
' https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
' https://images.unsplash.com/photo-1564135624576-c5c88640f235',
' https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
' https://images.unsplash.com/photo-1522364723953-452d3431c267',
' https://images.unsplash.com/photo-1513938709626-033611b8cc03',
' https://images.unsplash.com/photo-1507143550189-fed454f93097',
' https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
' https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
' https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
' https://images.unsplash.com/photo-1516972810927-80185027ca84',
' https://images.unsplash.com/photo-1550439062-609e1531270e',
]

Percorrer a lista de URLs baixando cada imagem na mesma pasta que contém seu projeto. Exiba o tempo gasto para baixar as imagens subtraindo a hora de término da hora de início.

start_time = time.perf_counter()
para img_url em img_urls:
img_bytes = requests.get (img_url).content
img_name = img_url.split('/')[3]
img_name = f'{img_name}.jpg'
com aberto (img_name, 'wb') como img_file:
img_file.write (img_bytes)
imprimir(f'{img_name} foi baixado...')
hora_final = hora.perf_counter()
imprimir(f'Concluído em {hora_de_fim - hora_de_início} segundos')

O programa leva cerca de 22 segundos para baixar as 12 imagens. Pode variar para você, pois o tempo necessário para baixar as imagens também depende da velocidade da sua internet.

Modifique o programa para usar encadeamento usando o módulo concurrent.features. Em vez de um loop, use uma função. Esta é a função que você passará para o executor instância.

importar solicitações de
importar tempo
importar concorrentes.futuros

img_urls = [
' https://images.unsplash.com/photo-1524429656589-6633a470097c',
' https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
' https://images.unsplash.com/photo-1564135624576-c5c88640f235',
' https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
' https://images.unsplash.com/photo-1522364723953-452d3431c267',
' https://images.unsplash.com/photo-1513938709626-033611b8cc03',
' https://images.unsplash.com/photo-1507143550189-fed454f93097',
' https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
' https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
' https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
' https://images.unsplash.com/photo-1516972810927-80185027ca84',
' https://images.unsplash.com/photo-1550439062-609e1531270e',
]

start_time = time.perf_counter()

defdownload_image(img_url):
img_bytes = requests.get (img_url).content
img_name = img_url.split('/')[3]
img_name = f'{img_name}.jpg'
com aberto (img_name, 'wb') como img_file:
img_file.write (img_bytes)
imprimir(f'{img_name} foi baixado...')

com concorrentes.futuros. ThreadPoolExecutor() como executor:
executor.map (download_image, img_urls)

hora_final = hora.perf_counter()

imprimir(f'Concluído em {hora_de_fim-hora_de_início} segundos')

Depois de introduzir o threading. O tempo reduz significativamente. Demorou apenas 4 segundos para concluir a execução do programa.

Cenários Adequados para Threading

Alguns dos cenários adequados para threading são:

  • Tarefas vinculadas de E/S: Se o programa passar a maior parte do tempo esperando a conclusão das operações de entrada ou saída. O encadeamento pode melhorar o desempenho, permitindo que outras tarefas sejam executadas enquanto aguarda a conclusão das operações de E/S.
  • Raspagem da web: A raspagem da Web envolve fazer solicitações HTTP e analisar respostas HTML. O encadeamento ajuda a acelerar o processo, permitindo que você faça várias solicitações simultaneamente.
  • Tarefas vinculadas à CPU: o encadeamento pode ajudar a melhorar o desempenho, permitindo que várias tarefas sejam executadas em paralelo.

Familiarize-se com o Threading em outros idiomas

Python não é a única linguagem que suporta threading. A maioria das linguagens de programação oferece suporte a alguma forma de threading. É importante se familiarizar com a implementação de threads em outras linguagens. Isso o equipa com as habilidades necessárias para lidar com diferentes cenários em que o encadeamento pode ser aplicado.