DEV Community

João Cláudio (joaoclaudio)
João Cláudio (joaoclaudio)

Posted on

Desvendando o async e await no Python: Guia para Programação Assíncrona Prof. João Cláudio Nunes Carvalho

Prof. João Cláudio Nunes Carvalho

No universo da programação Python, a eficiência e a capacidade de resposta das aplicações são cruciais. Para tarefas que envolvem operações de entrada e saída (I/O), como requisições de rede, acesso a bancos de dados ou leitura e escrita de arquivos, a programação assíncrona surge como uma ferramenta poderosa. No coração dessa abordagem em Python, encontramos as palavras-chave async e await, que permitem a escrita de código concorrente de forma mais limpa e legível.

O que é Programação Assíncrona?
Tradicionalmente, o código Python é executado de forma síncrona, ou seja, uma instrução após a outra, em sequência. Se uma tarefa demorada, como o download de um arquivo, é iniciada, todo o programa fica bloqueado, aguardando a sua conclusão. A programação assíncrona, por outro lado, permite que o programa inicie uma tarefa de longa duração e, enquanto espera pela sua finalização, execute outras tarefas. Isso não significa que o código está sendo executado em múltiplos processos ou threads simultaneamente, mas sim que o programa pode gerenciar múltiplas tarefas dentro de um único fluxo de execução, otimizando o tempo ocioso.

O Papel do async e await
As palavras-chave async and await foram introduzidas no Python 3.5 para facilitar a escrita de código assíncrono. Elas trabalham em conjunto com a biblioteca asyncio, que fornece a infraestrutura para executar e gerenciar tarefas assíncronas.

async def: Utilizada para declarar uma função como uma corrotina. Uma corrotina é uma função especial que pode ter sua execução pausada e retomada posteriormente. Ao ser chamada, uma corrotina não executa seu código imediatamente, mas retorna um objeto de corrotina.

await: Esta palavra-chave é usada dentro de uma corrotina para pausar a execução da mesma e aguardar o resultado de outra operação assíncrona. Enquanto a corrotina está "aguardando" (awaiting), o loop de eventos do asyncio pode executar outras tarefas que estão prontas para serem processadas.

Como Funciona na Prática
Para que o código assíncrono seja executado, é necessário um loop de eventos. O asyncio é responsável por gerenciar esse loop. A função asyncio.run(), introduzida no Python 3.7, simplifica o processo de inicialização e execução de uma corrotina principal.

Exemplo Básico:

Python

import asyncio
import time

async def saudacao(nome, delay):
print(f"Olá, {nome}! Aguardando {delay} segundos...")
await asyncio.sleep(delay)
print(f"Tchau, {nome}!")

async def main():
inicio = time.time()
await saudacao("Alice", 2)
await saudacao("Bob", 1)
fim = time.time()
print(f"Tempo total de execução: {fim - inicio:.2f} segundos")

asyncio.run(main())
Neste exemplo, saudacao é uma corrotina que simula uma operação demorada usando asyncio.sleep(). A função main orquestra a execução. Note que as saudações são executadas sequencialmente, pois o await na primeira chamada de saudacao bloqueia a execução de main até que a primeira saudação seja concluída.

Executando Tarefas Concorrentemente
A verdadeira magia do async e await se revela quando executamos múltiplas tarefas concorrentemente. Para isso, podemos usar asyncio.gather().

Exemplo com Concorrência:

Python

import asyncio
import time

async def saudacao(nome, delay):
print(f"Olá, {nome}! Aguardando {delay} segundos...")
await asyncio.sleep(delay)
print(f"Tchau, {nome}!")

async def main():
inicio = time.time()
await asyncio.gather(
saudacao("Alice", 2),
saudacao("Bob", 1)
)
fim = time.time()
print(f"Tempo total de execução: {fim - inicio:.2f} segundos")

asyncio.run(main())
Ao utilizar asyncio.gather(), as duas chamadas a saudacao são iniciadas quase simultaneamente. O await asyncio.gather(...) aguardará a conclusão de ambas. O tempo total de execução será próximo ao da tarefa mais longa (2 segundos), e não a soma dos tempos (3 segundos), demonstrando o ganho de eficiência.

Vantagens do Uso de async e await
Melhor Desempenho para Operações I/O-bound: Aplicações que passam a maior parte do tempo esperando por respostas de rede, bancos de dados ou sistemas de arquivos se beneficiam enormemente, pois o programa pode realizar outras tarefas durante esses períodos de espera.

Código Mais Legível: Comparado a outras abordagens de programação concorrente, como callbacks ou threads, o async/await permite escrever código que se assemelha mais à programação síncrona, tornando-o mais fácil de entender e manter.

Recursos Eficientes: Por executar em uma única thread, o asyncio consome menos recursos de memória em comparação com a criação de múltiplas threads para tarefas concorrentes.

Casos de Uso Comuns
A programação assíncrona com async e await é ideal para:

Servidores Web e APIs: Frameworks como FastAPI e aiohttp são construídos sobre asyncio para lidar com um grande número de requisições simultâneas de forma eficiente.

Clientes de API: Realizar múltiplas chamadas a APIs de terceiros de forma concorrente.

Aplicações de Chat e Streaming: Manter conexões abertas e lidar com a troca de mensagens em tempo real.

Web Scraping: Fazer o download de várias páginas da web simultaneamente.

Em resumo, async e await no Python, em conjunto com a biblioteca asyncio, fornecem uma sintaxe elegante e poderosa para a construção de aplicações performáticas e escaláveis, especialmente quando a carga de trabalho é dominada por operações de entrada e saída. A adoção desse paradigma pode ser um diferencial significativo no desenvolvimento de software moderno e responsivo.

Top comments (0)