Como aprimorar seu código Python com simultaneidade e paralelismo

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.

  • 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.
  • O paralelismo, por outro lado, envolve a execução de múltiplas tarefas genuinamente em paralelo. Normalmente tira vantagem de 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.
  •   13 práticas recomendadas para proteger microsserviços

    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:

  • 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.
  • 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.
  • 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.
  • Escalabilidade: Tanto a simultaneidade quanto o paralelismo são essenciais para a construção de sistemas escaláveis.
  • Preparado para o 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.

    Módulo de threading do Python 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',
    ]


    def download_url(url):
        response = requests.get(url)
        print(f"Downloaded {url} - Status Code: {response.status_code}")


    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")


    start_time = time.time()
    threads = []

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


    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.

      Como proteger as células da edição no Planilhas Google

    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 funcionar com asyncio:

     import asyncio
    import aiohttp
    import time

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


    async def download_url(url):
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                content = await response.text()
                print(f"Downloaded {url} - Status Code: {response.status}")


    async def main():
        
        tasks = [download_url(url) for url in urls]

        
        await asyncio.gather(*tasks)

    start_time = time.time()


    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 asyncio e aproveitar as vantagens das operações de E/S assíncronas. Isso pode ser mais eficiente do que threading para tarefas vinculadas a E/S.

      Mais de 5.000 nomes engraçados do Kahoot

    Paralelismo em Python

    Você pode implementar o paralelismo usando Módulo de multiprocessamento do Pythonque permite aproveitar ao máximo os processadores multicore.

    Multiprocessamento em Python

    O módulo de multiprocessamento do Python 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',
    ]


    def download_url(url):
        response = requests.get(url)
        print(f"Downloaded {url} - Status Code: {response.status_code}")

    def main():
        
        num_processes = len(urls)
        pool = multiprocessing.Pool(processes=num_processes)

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

        
        pool.close()
        pool.join()

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

    main()

    Neste exemplo, o multiprocessamento gera vários processos, permitindo que a função download_url 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 a simultaneidade ao lidar com tarefas vinculadas a E/S, como ler e gravar em arquivos ou fazer solicitações de rede, e quando restrições de memória forem uma preocupação.

    Use o multiprocessamento quando 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.