No mundo da programação, o conceito de "não bloqueio" é difundido. Os desenvolvedores de JavaScript costumam usar o termo “assíncrono” porque é um dos pontos fortes do JavaScript. No entanto, para compreender verdadeiramente a programação assíncrona, é essencial compreender os conceitos de programação simultânea e paralela.
Quando várias entidades independentes trabalham simultaneamente, a programação é concorrente. Isso não significa necessariamente que essas tarefas sejam executadas exatamente ao mesmo tempo. Em vez disso, significa que as tarefas progridem ao longo do tempo através do compartilhamento de recursos, como o tempo de CPU. A principal vantagem da programação simultânea é a sua robustez: se um processo falhar, o resto do seu programa continua a funcionar.
Se um algoritmo pode dividir seu trabalho em várias partes, ele é paralelo. Quanto mais processadores você tiver, mais se beneficiará do paralelismo. A programação paralela eficiente otimiza os recursos das máquinas modernas para melhor desempenho.
Exemplo de simultaneidade:
Imagine que você está preparando uma refeição onde precisa grelhar uma carne e fazer um molho. Você começa colocando a carne na churrasqueira. Enquanto a carne grelha, você pica os tomates e outros vegetais para o molho. Então, você começa a ferver o molho enquanto verifica ocasionalmente a carne. Aqui, ambas as tarefas (grelhar a carne e fazer o molho) estão em andamento, mas você está alternando sua atenção entre elas. Isso representa simultaneidade.
Exemplo de paralelismo:
Agora, digamos que você tenha um amigo para ajudá-lo. Enquanto você se concentra em grelhar a carne, seu amigo se encarrega de preparar o molho. Ambas as tarefas estão sendo realizadas simultaneamente, sem a necessidade de alternar a atenção entre elas. Isso representa paralelismo.
A programação assíncrona envolve o tratamento de operações de entrada/saída (E/S) que ocorrem fora do seu programa, como entrada do usuário, impressão em um terminal, leitura de um soquete ou gravação em disco. As principais características da E/S assíncrona são:
O tempo gasto pela operação não depende da CPU. Em vez disso, depende de fatores como velocidade do disco, latência da rede e outras condições externas.
O programa não pode prever quando a operação terminará.
Para serviços com E/S significativa (como servidores web, bancos de dados e scripts de implantação), a otimização dessas operações pode melhorar muito o desempenho.
Vamos ver exemplos de código bloqueador e código não bloqueador.
Considere um programa simples:
import time def task(): time.sleep(2) print("Hello") for _ in range(3): task()
Neste programa síncrono, cada tarefa espera a conclusão da anterior, causando atrasos.
Agora, vamos ver uma versão assíncrona usando asyncio:
import asyncio async def task(): await asyncio.sleep(2) print("Hello") async def main(): tasks = [task() for _ in range(3)] await asyncio.gather(*tasks) asyncio.run(main())
Neste programa assíncrono, as tarefas são executadas simultaneamente, reduzindo o tempo total de execução. Vamos explorar os componentes da programação assíncrona.
Loops de eventos, corrotinas e futuros são os elementos essenciais de um programa Python assíncrono.
Loop de eventos: gerencia a alternância de tarefas e o fluxo de execução, monitorando as tarefas a serem executadas de forma assíncrona.
Corrotinas: Funções especiais que podem ser pausadas e retomadas, permitindo que outras tarefas sejam executadas durante a espera. Uma corrotina especifica onde na função o evento de troca de tarefas deve ocorrer, retornando o controle ao loop de eventos. As corrotinas normalmente são criadas pelo loop de eventos e armazenadas internamente em uma fila de tarefas.
Futuros: Espaços reservados para resultados de corrotinas, armazenando o resultado ou exceções. Assim que o loop de eventos inicia uma corrotina, é criado um futuro correspondente que armazena o resultado da corrotina, ou uma exceção se uma tiver sido lançada durante a execução da corrotina.
Com as partes cruciais da programação assíncrona em Python explicadas, vamos escrever algum código.
Agora que você entende o padrão de programação assíncrona, vamos escrever um pequeno script e analisar a execução. Aqui está um script assíncrono simples:
import asyncio async def task(): await asyncio.sleep(2) print("Hello") async def main(): tasks = [task() for _ in range(3)] await asyncio.gather(*tasks) asyncio.run(main())
No código acima, estamos tentando continuar a execução de outras tarefas mesmo que outra em execução esteja dormindo (bloqueando). Observe a palavra-chave async na frente da tarefa e das funções principais.
Essas funções agora são corrotinas.
As funções de corrotinas em Python são precedidas pela palavra-chave async. A função main() aqui é o coordenador de tarefas ou nosso loop de eventos único, pois executa todas as tarefas usando o método async.gather. A função asyncio.gather executa objetos aguardáveis simultaneamente.
Saída:
Hello Hello Hello Program executed in 2.01 seconds.
Quando cada tarefa atinge await asyncio.sleep(2), ela simplesmente vai para a próxima tarefa e volta quando terminar. É como dizer: "Vou dormir por 2 segundos. Faça outra coisa."
Vamos ver a versão síncrona para uma comparação rápida.
import time def task(): time.sleep(2) print("Hello") for _ in range(3): task()
No código acima, seguimos o método de programação tradicional em Python. Você notará que a execução do processo levará muito mais tempo.
Saída:
Hello Hello Hello Program executed in 6.01 seconds.
Agora você pode notar o tempo de execução. Pense em time.sleep() como uma tarefa de bloqueio e asyncio.sleep() como uma tarefa longa ou sem bloqueio. Na programação assíncrona, o benefício de aguardar algo, como asyncio.sleep(), é que a função circundante pode ceder temporariamente o controle para outra função que está pronta para ser executada imediatamente.
Compreendidos alguns exemplos básicos de programação assíncrona em Python, vamos explorar as regras da programação assíncrona em Python.
Corotinas: As corrotinas não podem ser executadas diretamente. Se você tentar executar uma função de corrotina diretamente, ela retornará um objeto de corrotina. Em vez disso, use asyncio.run():
import asyncio async def hello(): await asyncio.sleep(1) print('Hello') asyncio.run(hello())
Objetos Aguardáveis: Corrotinas, futuros e tarefas são os principais objetos aguardáveis. As corrotinas Python são aguardáveis e podem ser aguardadas de outras corrotinas.
Await Palavra-chave:await só pode ser usado em funções assíncronas.
async def hello(): await asyncio.sleep(1) print("Hello")
Compatibilidade: Nem todos os módulos Python são compatíveis com programação assíncrona. Por exemplo, substituir await asyncio.sleep() por time.sleep() causará um erro. Você pode verificar a lista de módulos compatíveis e mantidos aqui.
Na próxima seção, exploraremos um uso comum de programação assíncrona, solicitações HTTP.
Vamos dar uma olhada no seguinte trecho de código:
import aiohttp import asyncio async def fetch(session, city): url = f"https://www.prevision-meteo.ch/services/json/{city}" async with session.get(url) as response: data = await response.json() print(f"Temperature at {city}: {data['current_condition']['tmp']} C") async def main(): async with aiohttp.ClientSession() as session: cities = ['paris', 'toulouse', 'marseille'] tasks = [fetch(session, city) for city in cities] await asyncio.gather(*tasks) asyncio.run(main())
No código acima, criamos duas funções assíncronas: uma para buscar dados da URL prevision-meteo e uma função principal para executar os processos no código Python. O objetivo é enviar solicitações HTTP GET assíncronas para recuperar temperaturas e imprimir as respostas.
Nas funções main e fetch, usamos async with. Na função de busca, async with garante que a conexão seja fechada corretamente. Na função principal, garante que a ClientSession seja fechada após a conclusão das solicitações. Essas práticas são importantes na codificação assíncrona em Python para gerenciar recursos de forma eficiente e evitar vazamentos.
Na última linha da função principal, usamos await asyncio.gather(*tasks). No nosso caso, ele executa todas as tarefas simultaneamente, permitindo ao programa enviar múltiplas solicitações HTTP simultaneamente. Usar await garante que o programa aguarde a conclusão de todas as tarefas antes de prosseguir.
Saída:
Temperature at marseille: 25 C Temperature at toulouse: 24 C Temperature at paris: 18 C Program executed in 5.86 seconds.
Código:
import requests import time def fetch(city): url = f"https://www.prevision-meteo.ch/services/json/{city}" response = requests.get(url) data = response.json() print(f"Temperature at {city}: {data['current_condition']['tmp']} C") def main(): cities = ['paris', 'toulouse', 'marseille'] for city in cities: fetch(city) start_time = time.time() main() print(f"Program executed in {time.time() - start_time:.2f} seconds.")
Saída:
Temperature at Paris: 18 C Temperature at Toulouse: 24 C Temperature at Marseille: 25 C Program executed in 9.01 seconds.
O modelo assíncrono tem melhor desempenho quando:
Há um grande número de tarefas, garantindo que pelo menos uma tarefa sempre possa progredir.
As tarefas envolvem E/S significativas, fazendo com que um programa assíncrono perca muito tempo bloqueando quando outras tarefas poderiam estar em execução.
As tarefas são amplamente independentes, minimizando a comunicação entre tarefas (e, portanto, uma tarefa aguardando a outra).
Neste tutorial, abordamos:
Os conceitos de programação assíncrona e conceitos relacionados.
Uso efetivo de async/await.
Fazendo solicitações HTTP assíncronas com aiohttp.
Os benefícios da programação assíncrona.
Obrigado pela leitura. A segunda parte abordará programação assíncrona com Django.
Documentação do Python: corrotinas e tarefas
Documentação do Python: asyncio - E/S assíncrona
documentação aiohttp
Bibliotecas Aio
Simultaneidade vs Paralelismo
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3