Python tem reputação de ser lento para servidores web — reputação merecida quando se usa Flask com WSGI de forma síncrona, mas injusta para o Python assíncrono moderno. FastAPI com asyncio pode lidar com milhares de conexões concorrentes em um único processo, comparável a Node.js e Go para workloads I/O bound. Entender o modelo de async/await não é opcional para Python moderno em cenários de alta concorrência.
O problema do I/O bloqueante
Em Python síncrono, quando você faz uma query ao banco (db.execute(query)), o processo inteiro fica bloqueado aguardando a resposta — nenhuma outra request pode ser processada nesse tempo. Com 100 requests concorrentes cada uma esperando 50ms de banco, você precisa de 100 threads ou processos para não enfileirar. Threads têm overhead de memória (stack de 8MB por thread) e o GIL do Python limita o paralelismo real de CPU. Asyncio resolve de outra forma: event loop único que intercala múltiplas coroutines, trocando o controle quando uma está aguardando I/O — sem threads adicionais.
A palavra-chave await marca os pontos onde a coroutine cede o controle para o event loop enquanto aguarda uma operação assíncrona completar. async def define uma coroutine — uma função que pode ser pausada e retomada. O event loop executa todas as coroutines em um único thread, garantindo ausência de race conditions sem locks (o GIL torna escrita/leitura atômica em CPython). asyncio.gather() executa múltiplas coroutines concorrentemente — buscar de 5 APIs em paralelo leva o tempo da mais lenta, não a soma de todas.
FastAPI: o framework para APIs modernas
FastAPI combina performance (assíncrono nativo, um dos frameworks Python mais rápidos), produtividade (code-first OpenAPI automático, Pydantic para validação e serialização), e DX excepcional (type hints geram documentação interativa, erros de validação automáticos com mensagens claras). A documentação Swagger UI em /docs e ReDoc em /redoc são geradas automaticamente a partir das definições de tipo — zero configuração extra.
Injeção de dependência é o padrão central do FastAPI: Depends() injeta automaticamente conexões de banco, usuário autenticado, configurações, e qualquer recurso compartilhado. Cada função de dependência é chamada apenas uma vez por request, com resultado cacheado e compartilhado entre todos os handlers que a dependem. Background tasks (BackgroundTasks) executam código após retornar a resposta ao cliente — envio de email, atualização de cache, logging assíncrono — sem bloquear a response. Middleware de CORS, rate limiting, logging e autenticação se encaixam no mesmo modelo de dependency injection.
Banco de dados assíncrono com SQLAlchemy 2.x e asyncpg
SQLAlchemy 2.x tem suporte nativo a async com AsyncSession e create_async_engine. Combinado com asyncpg (driver PostgreSQL assíncrono puro em Python), o stack completo é não-bloqueante do handler HTTP até o banco. Um único worker FastAPI pode lidar com centenas de queries de banco concorrentes — scale vertical antes de scale horizontal. Connection pool gerenciado pelo engine reutiliza conexões eficientemente, e async_scoped_session garante que cada request use sua própria sessão isolada sem vazamento entre requests.
Para caching, aiocache integra Redis assíncrono com decorators simples: @cached(ttl=300) cacheia o resultado de endpoints por 5 minutos sem modificar a lógica. aiofiles para operações de arquivo não-bloqueantes, httpx para requisições HTTP assíncronas a APIs externas. O padrão de circuit breaker com tenacity ou pybreaker protege contra falhas em cascata: após N falhas consecutivas em um serviço externo, o circuit breaker abre e retorna erro imediatamente sem esperar timeout, liberando o event loop para processar outras requests enquanto o serviço externo se recupera.
Testes e deployment
Testar código assíncrono requer pytest-asyncio: marque os testes com @pytest.mark.asyncio ou configure asyncio_mode = "auto" no pytest.ini. httpx.AsyncClient com app=app faz requests de teste sem servidor real, com suporte a mocking de dependências via app.dependency_overrides. Para banco de dados, use uma instância de teste separada com migrations aplicadas, e rollback cada teste em uma transaction que nunca comita — testes isolados e rápidos sem limpeza manual.
Deploy: Uvicorn é o ASGI server para produção, Gunicorn gerencia múltiplos workers Uvicorn para utilizar múltiplos núcleos de CPU. A regra para número de workers é 2 × CPUs + 1. Container Docker com imagem python-slim e multi-stage build mantém a imagem abaixo de 150MB. Health checks no Kubernetes devem usar /health/live (liveness: o processo está vivo?) e /health/ready (readiness: o processo está pronto para receber tráfego, com banco conectado?) — separação crítica para evitar que K8s envie tráfego para pods que ainda estão inicializando conexões.
Tem um projeto em mente?
Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.