Asyncio Avançado: Programação Assíncrona Eficiente em Python
1. Conceitos Fundamentais
1.1 Eventos e Loop
O event loop é o coração do asyncio, gerenciando a execução de coroutines.
import asyncio
async def tarefa():
print("Início")
await asyncio.sleep(1)
print("Fim")
asyncio.run(tarefa())
async defdefine uma coroutine, que só é executada quandoawaité chamado.awaitpausa a coroutine sem bloquear o event loop, permitindo que outras tarefas rodem.
1.2 Corroutines vs Tasks
Coroutine: função assíncrona, executada pelo event loop.
Task: coroutine agendada para execução concurrentemente.
async def main():
t1 = asyncio.create_task(tarefa())
t2 = asyncio.create_task(tarefa())
await t1
await t2
asyncio.run(main())
Tasks permitem executar múltiplas coroutines simultaneamente.
2. Concorrência Avançada
2.1 asyncio.gather
Executa múltiplas coroutines concorrentemente e retorna resultados:
results = await asyncio.gather(tarefa(), tarefa())
Mantém ordem dos resultados, mesmo que uma coroutine termine antes da outra.
2.2 asyncio.wait
Permite esperar por múltiplas tarefas com controle de timeout ou retorno parcial:
done, pending = await asyncio.wait([t1, t2], timeout=1)
Útil em pipelines onde algumas tarefas podem expirar.
2.3 Controle de Concurrency
Limita o número de coroutines simultâneas com Semáforos:
sem = asyncio.Semaphore(3)
async def worker(n):
async with sem:
await asyncio.sleep(1)
print(f"Tarefa {n} concluída")
tasks = [worker(i) for i in range(10)]
await asyncio.gather(*tasks)
Evita sobrecarregar recursos externos (APIs, banco de dados, rede).
3. Asyncio e I/O Avançado
3.1 Requisições HTTP assíncronas
Com aiohttp, podemos realizar múltiplas requisições em paralelo:
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()
urls = ["https://example.com" for _ in range(5)]
results = await asyncio.gather(*(fetch(url) for url in urls))
Extremamente mais rápido que requests sequencial, porque não bloqueia o loop.
3.2 Leitura e escrita assíncrona de arquivos
import aiofiles
async def escreve_arquivo(nome, texto):
async with aiofiles.open(nome, mode="w") as f:
await f.write(texto)
await escreve_arquivo("saida.txt", "Conteúdo assíncrono")
Permite manipulação de arquivos sem bloquear I/O, útil em pipelines de dados massivos.
4. Padrões de Design Assíncronos
4.1 Produtor-Consumidor
import asyncio
import random
fila = asyncio.Queue()
async def produtor():
for i in range(10):
await fila.put(i)
print(f"Produziu {i}")
await asyncio.sleep(random.random())
async def consumidor():
while True:
item = await fila.get()
print(f"Consumiu {item}")
fila.task_done()
if item == 9: break
await asyncio.gather(produtor(), consumidor())
asyncio.Queueé thread-safe e não bloqueante.Ideal para pipelines de processamento assíncrono.
4.2 Timeout e Cancelamento
async def tarefa_lenta():
await asyncio.sleep(10)
try:
await asyncio.wait_for(tarefa_lenta(), timeout=2)
except asyncio.TimeoutError:
print("Timeout ocorrido")
Garante controle sobre tarefas longas e evita travamento do loop.
5. Estratégias Avançadas
5.1 Combinar Tasks e Gather com timeout
tasks = [asyncio.create_task(fetch(url)) for url in urls]
done, pending = await asyncio.wait(tasks, timeout=5)
Permite coletar resultados parciais e cancelar tasks pendentes.
5.2 Limitar concorrência global
Combinar
Semaphorecom pipeline de milhares de coroutines:
sem = asyncio.Semaphore(10)
async def limitada(url):
async with sem:
return await fetch(url)
Evita sobrecarga em APIs externas ou banco de dados.
5.3 Loop customizado
Para cenários avançados, podemos controlar o event loop manualmente:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
tasks = [loop.create_task(fetch(url)) for url in urls]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()
Útil em integração com frameworks externos.
6. Boas Práticas Profissionais
Prefira async/await em vez de callbacks para clareza e manutenção.
Use aiohttp, aiofiles ou bibliotecas que liberam I/O para máxima performance.
Combine
SemaphoreeQueuepara limitar e organizar concorrência.Monitore timeouts e cancelamentos, evitando bloqueio do loop.
Evite misturar threads e asyncio, prefira asyncio puro ou multiprocessing para CPU-bound.
Documente claramente fluxo assíncrono e pontos de concorrência.
7. Aplicações Profissionais
Web scraping massivo assíncrono
Integração com APIs externas de forma eficiente
ETL e pipelines de dados assíncronos
Monitoramento e coleta de dados em tempo real
Serviços de chat, websockets e microservices assíncronos
8. Conclusão
Asyncio permite programação concorrente eficiente sem múltiplas threads.
Ferramentas avançadas incluem gather, wait, Semaphore, Queue, timeout e cancelamento.
Combinando com aiohttp, aiofiles e design de pipelines, é possível criar aplicações escaláveis e responsivas.
Ideal para I/O-bound massivo, pipelines de dados e microservices modernos.

Comentários
Postar um comentário