Programação assíncrona permite múltiplas tarefas simultâneas. Ela não espera uma operação terminar para iniciar outra. Primeiramente, isso é excelente para operações de I/O. Por exemplo, chamadas de rede, acesso a banco ou leitura de arquivos. Em vez de bloquear, o código cede a vez para outra tarefa. Quando o resultado chega, a execução retorna ao ponto original. A voz passiva é usada aqui: “um event loop é usado para gerenciar as tarefas”. Quando utilizar frameworks assíncronos? Em aplicações com muitas conexões simultâneas. Chats, dashboards em tempo real ou proxies são exemplos perfeitos. Três frameworks se destacam: FastAPI, Sanic e Aiohttp. Cada um tem características e níveis de maturidade diferentes. Vamos explorar cada um em detalhes. Ao final, você saberá qual escolher para seu projeto.
FastAPI: o mais popular e completo
FastAPI é assíncrono por padrão, mas aceita funções síncronas. Ele é construído sobre o Starlette e usa Pydantic para validação. Sua maior força é a documentação automática (Swagger e ReDoc). Além disso, é extremamente rápido, comparável ao Node.js e Go. Quando usar FastAPI? Em APIs REST, microsserviços e projetos novos. Ele tem suporte nativo a WebSockets e background tasks. A curva de aprendizado é suave para quem conhece Flask. A voz passiva é aplicada: “as dependências são resolvidas de forma assíncrona”. Um exemplo simples de endpoint assíncrono:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from fastapi import FastAPI import httpx import asyncio app = FastAPI() @app.get('/dados-assincronos') async def buscar_dados(): async with httpx.AsyncClient() as cliente: # Chamada assíncrona: não bloqueia resposta1 = await cliente.get('https://api1.example.com/dados') resposta2 = await cliente.get('https://api2.example.com/status') return { 'api1': resposta1.json(), 'api2': resposta2.json() } # Rode com: uvicorn main:app --reload |
As duas chamadas rodam de forma concorrente? Não exatamente.
Elas ainda são sequenciais (uma após a outra).
Para paralelismo real, use asyncio.gather().
FastAPI lida com milhares de conexões simultâneas facilmente.
Sanic: o veterano da velocidade
Sanic foi criado especificamente para ser rápido e assíncrono. Ele lembra o Flask na sintaxe, mas roda sobre asyncio. Quando usar Sanic? Em projetos que exigem máxima performance bruta. Por exemplo, servidores de jogos ou streaming de dados. Sanic suporta workers múltiplos e é estável há anos. Porém, sua comunidade é menor que a do FastAPI. A documentação é boa, mas menos abrangente. Uma vantagem é o servidor embutido pronto para produção. Não precisa de Gunicorn ou Uvicorn separados. Veja um exemplo de Sanic assíncrono:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from sanic import Sanic from sanic.response import json import asyncio app = Sanic("MeuAppAssincrono") @app.route("/slow") async def endpoint_lento(request): await asyncio.sleep(2) # Simula I/O return json({"mensagem": "Processado após 2 segundos"}) @app.route("/fast") async def endpoint_rapido(request): return json({"mensagem": "Resposta imediata"}) if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, workers=4) |
Enquanto /slow dorme, outras requisições são atendidas.
O event loop do Sanic gerencia isso automaticamente.
Isso é o poder do assíncrono: nenhum bloqueio desnecessário.
Aiohttp: o framework minimalista e direto
Aiohttp é cliente e servidor HTTP assíncrono em um só pacote. Ele não tem validação de dados ou documentação automática. Por outro lado, oferece controle total e baixo overhead. Quando usar Aiohttp? Em projetos onde você quer mínimas abstrações. Também é excelente para proxies, crawlers ou servidores customizados. A curva de aprendizado é mais íngreme que a do FastAPI. Você precisa entender asyncio profundamente. A voz passiva é vista: “as rotas são registradas manualmente nas tabelas”. Exemplo de um servidor simples com Aiohttp:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from aiohttp import web import asyncio async def handle_requisicao(request): nome = request.match_info.get('nome', 'Anônimo') await asyncio.sleep(0.5) # Simula I/O return web.Response(text=f"Olá, {nome}!") async def iniciar_servidor(): app = web.Application() app.router.add_get('/saudacao/{nome}', handle_requisicao) return app if __name__ == '__main__': web.run_app(iniciar_servidor(), port=8080) |
Esse código é leve e eficiente. Não há validação automática de parâmetros. Você mesmo precisa extrair e verificar os dados. Aiohttp é ideal para quem quer entender profundamente o asyncio.
Comparação final e quando escolher cada um
FastAPI é a escolha para a maioria dos projetos novos. Ele oferece documentação, validação e performance excelentes. Sanic é uma alternativa quando você precisa de velocidade pura. Aiohttp é para cenários onde o controle absoluto é necessário. A fórmula de throughput pode ajudar na decisão: \(Throughput = \frac{N_{\text{conexões}}}{T_{\text{médio resposta}}}\) Em sistemas assíncronos, o throughput é muito maior para I/O. Porém, para CPU intensivo, o assíncrono não traz vantagem. Portanto, avalie seu tipo de operação dominante. Comece com FastAPI se tiver dúvidas. Ele é o mais equilibrado entre poder e simplicidade. Lembre-se: programação assíncrona exige cuidado com race conditions. Use locks e semáforos quando necessário. Com essas ferramentas, você construirá backends escaláveis e modernos.