Use essas técnicas para executar código simultaneamente e fornecer uma experiência de usuário mais tranquila.

Principais conclusões

  • Simultaneidade e paralelismo são princípios fundamentais de execução de tarefas em computação, cada um com características distintas.
  • A simultaneidade permite a utilização eficiente de recursos e melhor capacidade de resposta dos aplicativos, enquanto o paralelismo é crucial para desempenho e escalabilidade ideais.
  • Python oferece opções para lidar com simultaneidade, como threading e programação assíncrona com asyncio, bem como paralelismo usando o módulo multiprocessing.

Simultaneidade e paralelismo são duas técnicas que permitem executar vários programas simultaneamente. Python tem múltiplas opções para lidar com tarefas simultaneamente e em paralelo, o que pode ser confuso.

Explore as ferramentas e bibliotecas disponíveis para implementar adequadamente a simultaneidade e o paralelismo em Python e como elas diferem.

Compreendendo a simultaneidade e o paralelismo

Simultaneidade e paralelismo referem-se a dois princípios fundamentais de execução de tarefas em computação. Cada um tem suas características distintas.

  1. Simultaneidade é a capacidade de um programa gerenciar múltiplas tarefas ao mesmo tempo sem necessariamente executá-las exatamente ao mesmo tempo. Gira em torno da ideia de intercalar tarefas, alternando entre elas de uma forma que pareça simultânea.
  2. Paralelismo, por outro lado, envolve a execução de múltiplas tarefas genuinamente em paralelo. Normalmente aproveita vários núcleos de CPU ou processadores. O paralelismo alcança uma verdadeira execução simultânea, permitindo que você execute tarefas com mais rapidez e é adequado para operações computacionalmente intensivas.

A importância da simultaneidade e do paralelismo

A necessidade de simultaneidade e paralelismo na computação não pode ser exagerada. Veja por que essas técnicas são importantes:

  1. Utilização de recursos: a simultaneidade permite a utilização eficiente dos recursos do sistema, garantindo que as tarefas progridam ativamente, em vez de aguardar ociosamente por recursos externos.
  2. Capacidade de resposta: a simultaneidade pode melhorar a capacidade de resposta dos aplicativos, especialmente em cenários que envolvem interfaces de usuário ou servidores web.
  3. Desempenho: o paralelismo é crucial para alcançar o desempenho ideal, especialmente em tarefas vinculadas à CPU, como cálculos complexos, processamento de dados e simulações.
  4. Escalabilidade: Tanto a simultaneidade quanto o paralelismo são essenciais para a construção de sistemas escaláveis.
  5. À prova de futuro: À medida que as tendências de hardware continuam a favorecer os processadores multicore, a capacidade de aproveitar o paralelismo se tornará cada vez mais necessária.

Simultaneidade em Python

Você pode obter simultaneidade em Python usando threading e programação assíncrona com a biblioteca asyncio.

Threading em Python

Threading é um mecanismo de simultaneidade Python que permite criar e gerenciar tarefas em um único processo. Threads são adequados para certos tipos de tarefas, especialmente aquelas que são vinculadas a E/S e podem se beneficiar da execução simultânea.

Python rosqueamento módulo fornece uma interface de alto nível para criar e gerenciar threads. Embora o GIL (Global Interpreter Lock) limite os threads em termos de paralelismo verdadeiro, eles ainda podem alcançar simultaneidade intercalando tarefas de forma eficiente.

O código abaixo mostra um exemplo de implementação de simultaneidade usando threads. Ele usa a biblioteca de solicitações Python para enviar uma solicitação HTTP, uma tarefa comum de bloqueio de E/S. Ele também usa o módulo de tempo para calcular o tempo de execução.

import requests
import time
import threading

urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]

# function to request a URL
defdownload_url(url):
response = requests.get(url)
print(f"Downloaded {url} - Status Code: {response.status_code}")

# Execute without threads and measure execution time
start_time = time.time()

for url in urls:
download_url(url)

end_time = time.time()
print(f"Sequential download took {end_time - start_time:.2f} seconds\n")

# Execute with threads, resetting the time to measure new execution time
start_time = time.time()
threads = []

for url in urls:
thread = threading.Thread(target=download_url, args=(url,))
thread.start()
threads.append(thread)

# Wait for all threads to complete
for thread in threads:
thread.join()

end_time = time.time()
print(f"Threaded download took {end_time - start_time:.2f} seconds")

Ao executar este programa, você verá o quão mais rápidas são as solicitações encadeadas do que as solicitações sequenciais. Embora a diferença seja apenas uma fração de segundo, você tem uma noção clara da melhoria de desempenho ao usar threads para tarefas vinculadas a E/S.

Programação assíncrona com Asyncio

assíncio fornece um loop de eventos que gerencia tarefas assíncronas chamadas corrotinas. Corrotinas são funções que você pode pausar e retomar, tornando-as ideais para tarefas vinculadas a E/S. A biblioteca é particularmente útil para cenários onde as tarefas envolvem espera por recursos externos, como solicitações de rede.

Você pode modificar o exemplo anterior de envio de solicitação para trabalhar com assíncio:

import asyncio
import aiohttp
import time

urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]

# asynchronous function to request URL
asyncdefdownload_url(url):
asyncwith aiohttp.ClientSession() as session:
asyncwith session.get(url) as response:
content = await response.text()
print(f"Downloaded {url} - Status Code: {response.status}")

# Main asynchronous function
asyncdefmain():
# Create a list of tasks to download each URL concurrently
tasks = [download_url(url) for url in urls]

# Gather and execute the tasks concurrently
await asyncio.gather(*tasks)

start_time = time.time()

# Run the main asynchronous function
asyncio.run(main())

end_time = time.time()

print(f"Asyncio download took {end_time - start_time:.2f} seconds")

Usando o código, você pode baixar páginas da web simultaneamente usando assíncio e aproveite as operações de E/S assíncronas. Isso pode ser mais eficiente do que threading para tarefas vinculadas a E/S.

Paralelismo em Python

Você pode implementar o paralelismo usando Python multiprocessamento módulo, que permite aproveitar ao máximo os processadores multicore.

Multiprocessamento em Python

Python multiprocessamento O módulo fornece uma maneira de obter paralelismo criando processos separados, cada um com seu próprio interpretador Python e espaço de memória. Isso efetivamente ignora o Global Interpreter Lock (GIL), tornando-o adequado para tarefas vinculadas à CPU.

import requests
import multiprocessing
import time

urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]

# function to request a URL
defdownload_url(url):
response = requests.get(url)
print(f"Downloaded {url} - Status Code: {response.status_code}")

defmain():
# Create a multiprocessing pool with a specified number of processes
num_processes = len(urls)
pool = multiprocessing.Pool(processes=num_processes)

start_time = time.time()
pool.map(download_url, urls)
end_time = time.time()

# Close the pool and wait for all processes to finish
pool.close()
pool.join()

print(f"Multiprocessing download took {end_time-start_time:.2f} seconds")

main()

Neste exemplo, multiprocessamento gera vários processos, permitindo que o URL_download função seja executada em paralelo.

Quando usar simultaneidade ou paralelismo

A escolha entre simultaneidade e paralelismo depende da natureza das suas tarefas e dos recursos de hardware disponíveis.

Você pode usar simultaneidade ao lidar com tarefas vinculadas a E/S, como lendo e gravando em arquivos ou fazer solicitações de rede e quando as restrições de memória são uma preocupação.

Use o multiprocessamento quando você tiver tarefas vinculadas à CPU que podem se beneficiar do paralelismo verdadeiro e quando tiver um isolamento robusto entre tarefas, onde a falha de uma tarefa não deve afetar outras.

Aproveite as vantagens da simultaneidade e do paralelismo

Paralelismo e simultaneidade são formas eficazes de melhorar a capacidade de resposta e o desempenho do seu código Python. É importante compreender as diferenças entre esses conceitos e selecionar a estratégia mais eficaz.

Python oferece as ferramentas e os módulos necessários para tornar seu código mais eficaz por meio de simultaneidade ou paralelismo, independentemente de você estar trabalhando com processos vinculados à CPU ou vinculados à E/S.