Executando verificação de segurança...
17

Sim, Python é Lento (mas isso não importa pro seu app)

Python apanha por ser lento. Benchmarks mostram Rust e C++ dando de goleada. Go processa milhares de requests a mais por segundo. Os críticos não estão errados sobre os números de performance (ignorando o fato de que linguagens não podem realmente ser lentas ou rápidas).

Pra maioria das aplicações, no entanto, especialmente seu SaaS que é só um wrapper na API da OpenAI, tem muito contexto sendo deixado de lado. Outro dia um CEO que eu conheço tava me falando que queria usar Rust na startup dele. O que a startup faz? Um monte de requests pra OpenAI, como a maioria das novas.

Pessoal de software gosta de dizer que é diferente, mas quanto antes você aprender isso, melhor: pessoas falam sobre tendências. Primeiro, código tinha que ser performático, depois tinha que ser fácil de escrever, depois tinha que ser performático de novo... falta muito contexto nisso.

Engenharia de software não é sobre escrever código, é sobre analisar tradeoffs e tomar as melhores decisões possíveis baseado em todos os dados, e - como o Knuth disse - otimização prematura é a raiz de todo mal (97% das vezes). Vamos fazer essa decisão (Python ou uma linguagem mais rápida como Rust) como um engenheiro de software deveria fazer, analisando os tradeoffs.

O Processo Estruturado

Pra começar, o que é otimização prematura? Podemos pensar nisso de duas formas:

  1. Melhorar o que já funciona bem (e, portanto, não precisa ser melhorado)
  2. Tentar melhorar sem profiling adequado, ou seja, sem saber exatamente quão bem você está indo

A primeira é relevante, e deve ser sempre levada em conta. Tempo é finito, o custo de oportunidade de melhorar algo que funciona em vez de arrumar algo que não funciona (ou entregar novas features) é alto demais numa startup pra ser ignorado.

Aqui vamos falar mais sobre a segunda, já que quero mostrar como realmente tomar uma decisão usando todo o contexto.

Vamos começar com profiling, ou seja, medir quão bem estamos indo e em quais métricas específicas precisamos melhorar. Para uma API, geralmente isso significaria medir tempo de resposta, throughput (requests com sucesso por segundo), latência e algumas outras métricas, mas a gente ainda nem tem uma API de verdade nesse ponto, a gente tá decidindo o que usar.

Medindo o que não conseguimos medir

Precisamos usar uma variável proxy pra isso, ou seja, medir algo que não é diretamente o que precisamos medir, mas que assumimos (por alguma boa razão) que está intimamente relacionado ao que realmente precisamos, e portanto vai nos dar um resultado bem aproximado.

Como nossa aplicação principalmente faz requests pra serviços de IA, podemos começar assumindo que melhorar esse fluxo vai gerar o melhor resultado imediato, então vamos começar entendendo o que constitui um processo que envolve um request pra um serviço de IA.

Etapas do Request

Pensando de forma simplificada, o que acontece dentro da nossa API quando alguém faz algo (como gerar texto) é:

  1. Nossa API recebe uma requisição http (via rede)
  2. Python orquestra isso e o que precisa ser feito
  3. Fazemos uma query no banco de dados pra algo (talvez várias coisas até) como saber o usuário que está fazendo o request, suas permissões, uso
  4. Fazemos um request pra OpenAI ou qualquer outro provedor pra geração de texto (e precisamos esperar por isso)
  5. Armazenamos resultados no banco de dados pra que o usuário possa acessar
  6. Retornamos uma resposta pro cliente (outro request de rede)

Ok, agora que sabemos as etapas, podemos realmente pensar quanto tempo cada uma dessas levaria num request típico. Fazendo isso, conseguimos entender adequadamente qual otimização faria mais diferença (ainda melhor se for pelo menor esforço possível).

Vamos cronometrar cada uma dessas etapas (aproximadamente) e ver onde está nosso gargalo de performance:

  • Nossa API recebe uma requisição http: Isso é I/O de rede (Input, Output). Tipicamente 1-20ms dependendo da conexão do cliente e distância geográfica. Nada que possamos fazer aqui - os dados têm que viajar pela rede.
  • Python orquestra o request: Isso é CPU bound (nosso processador está realmente fazendo algo, não só esperando), mas mínimo. Fazer parse do JSON, validar inputs, lógica básica de negócio. Talvez 1-5ms total pra operações típicas de AI SaaS se feito corretamente.
  • Queries no banco de dados: Operação I/O bound clássica. Mesmo com indexação adequada, você está olhando 10-200ms por query dependendo da complexidade da query e localização do banco. Múltiplas queries multiplicam isso.
  • Chamada pra API da OpenAI: A grande. Geração de texto leva 500ms a 3 segundos dependendo do modelo e tamanho do prompt. Geração de imagem? 10-30 segundos. Isso é tempo puro de espera.
  • Armazenar resultados de volta: Outro write no banco, 10-100ms tipicamente.
  • Retornar resposta: I/O de rede de novo, similar a receber o request.

Vamos ser concretos aqui. Num request típico de IA:

  • Tempo total de execução Python: ~5ms
  • Tempo total esperando I/O: 1000-5000ms (ou muito mais dependendo da geração de IA)

Execução Python representa 0,1-0,5% do tempo total do request. Mesmo se fizéssemos Python magicamente infinitamente rápido, usuários nem perceberiam a diferença. A linguagem que escolhemos pra escrever nosso backend nem chega perto de ser o gargalo aqui, então o que é?

O Verdadeiro Gargalo: Operações I/O vs CPU

O problema de velocidade em aplicações de IA não é seu código Python - é esperar por todo o resto. Essa é a informação chave: a maioria das aplicações AI SaaS são I/O bound, não CPU bound.

Operações I/O Bound esperam por input/output completar. Requests de rede, queries de banco, operações de arquivo. O gargalo não é velocidade de computação - é esperar por dados.

Operações CPU Bound são limitadas por poder computacional. Matemática pesada, processamento de dados, algoritmos complexos. Essas realmente se beneficiam de linguagens mais rápidas.

Mas aqui está a questão - se seu SaaS está fazendo requests pra OpenAI, você é muito mais I/O bound. A escolha da linguagem se torna irrelevante quando 99% do seu tempo é gasto esperando por serviços externos. Mesmo se você conseguir fazer seu código de orquestração 10x mais rápido, você salvaria talvez 4ms de um request de 2000ms. Isso é 0,2% de melhoria.

Enquanto isso, se você fizer cache das queries do banco adequadamente, otimizar suas queries de banco, você estaria melhorando o que realmente faz diferença. Além disso, essas otimizações podem ser feitas não importando a linguagem, facilmente gerando 10-100x mais impacto que só trocar pro Rust.

Ok, mas você pode estar pensando "mesmo que não importe se python é lento pra orquestração, ainda está lidando com um request por vez". Isso nos leva pra próxima coisa, async.

Async Muda Tudo

Python moderno não é o Python single-threaded e que bloqueia outros requests de 2010.

Com async/await e frameworks como FastAPI, Python lida com workloads I/O bound tranquilamente. Enquanto um request espera a OpenAI responder, seu servidor Python processa centenas de outros requests.

@app.get("/generate")
async def generate_content(prompt: str, db: AsyncSession = Depends(get_db)):
    # Enquanto isso espera pelo banco de dados...
    user_data = await db.execute(select(User).where(...))

    # ...e isso espera pela OpenAI...
    response = await openai_client.chat.completions.create(...)

    # ...Python lida com outros requests concorrentemente
    await db.execute(insert(Generation).values(...))

    return response

Esse modelo de concorrência é perfeito pra AI SaaS. Você não é CPU bound mesmo, então async Python facilmente lida com milhares de requests concorrentes. Seu gargalo se torna rate-limit da API, conexões de banco, ou uso de memória - não a velocidade da linguagem.

Quando a Velocidade do Python Realmente Importa

Mesmo que seu caso provavelmente não seja um desses, existem casos onde a falta de velocidade do Python é realmente uma restrição:

  • Rodando modelos de ML localmente: Se você está fazendo inferência em Python em vez de chamar APIs, velocidade de computação importa. Mas a maioria das empresas AI SaaS usam APIs externas (OpenAI, Anthropic, etc.), não modelos locais.
  • Pré-processamento pesado de dados: Transformar datasets massivos antes de alimentar modelos. Mas de novo, a maioria das startups não tem datasets massivos inicialmente, e quando têm, usam ferramentas especializadas como Spark ou Dask.
  • Aplicações em tempo real: Trading de alta frequência, servidores de jogos, processamento de vídeo em tempo real. Essas são CPU bound e se beneficiam de linguagens mais rápidas. Mas se você está construindo ChatGPT para advogados, isso certamente não é você.
  • Computação matemática: Algoritmos complexos que não dependem de serviços externos. Processamento de sinais, computação científica, etc. De novo, não típico pra startups AI SaaS.

A questão é que esses representam casos extremos pra maioria das aplicações AI SaaS. Se seu modelo de negócio é "chamar API da OpenAI e adicionar alguma lógica de negócio ao redor" (que descreve a maioria das startups de IA), você é I/O bound por definição.

Se seu negócio chegar a um ponto onde Python não é suficiente, você pode até migrar só as partes que precisam ser performáticas - a maioria das bibliotecas pra coisas sensíveis a performance em python já são escritas em outra linguagem como Rust ou C++ e só chamadas pelo python.

O que Realmente Mata Sua Performance

Para 99% (até muito mais na verdade) dos SaaS de IA, os assassinos de performance são completamente diferentes:

Queries N+1 no banco de dados: Fazer chamadas separadas ao banco em loops em vez de queries bem feitas. Já vi codebases onde pegar 100 usuários leva 101 queries de banco em vez de 1. Isso não é problema de linguagem - é problema clássico de arquitetura.

# Isso mata performance - 100 queries de banco
for user_id in user_ids:
    user = await db.get(User, user_id)

# Isso é rápido - 1 query de banco
users = await db.execute(select(User).where(User.id.in_(user_ids)))

Índices faltando no banco de dados: Forçando full table scans em queries que deveriam ser instantâneas. Adicionar um índice pode transformar uma query de 5 segundos numa de 5 milissegundos.

Sem cache: Repetidamente chamando os mesmos endpoints com os mesmos parâmetros. Adicione um cache a essa resposta e veja acontecer instantaneamente na próxima vez.

Operações síncronas: Bloqueando todo seu request handler enquanto espera por I/O. Use async/await adequadamente.

Uso ruim de API: Fazendo 5 chamadas separadas pra API quando você poderia fazer em batch numa só.

Esses problemas causam degradação de performance de 10x a 100x. Arrume os problemas de arquitetura primeiro. Eles vão te dar muito mais retorno pelo investimento.

Os Verdadeiros Tradeoffs

Agora vamos pensar nesse problema como engenheiros de software de verdade.

Vantagens do Python pra SaaS de IA:

  • Entregue features rápido: O ecossistema do Python é incomparável para IA e integrações
  • Ache desenvolvedores facilmente: Pool de talentos muito maior que Rust ou Golang
  • Itere rapidamente: Ciclos de escrever, testar, fazer deploy são mais rápidos
  • Ecossistema comprovado: FastAPI, SQLAlchemy, OpenAI SDK - tudo simplesmente funciona

Vantagens do Rust:

  • Performance bruta: 2-5x mais rápido pra operações CPU-bound
  • Segurança de memória: Mais difícil escrever código com bug (uma vez que você passa da curva de aprendizado)
  • Menor uso de recursos: Importa se você está processando milhões de requests

A verdadeira pergunta: Qual é o seu gargalo?

Se você está fazendo computação pesada, linguagens como Rust podem fazer sentido, mas se você está fazendo chamadas de API pra OpenAI (como a maioria das startups de IA), seu gargalo é I/O de banco e rede, não performance de CPU.

Otimizar Python não vai ajudar quando 99% do tempo do seu request é esperando por serviços externos. E reescrever tudo em Rust vai levar meses enquanto seus concorrentes entregam novas features.

O CEO que falei antes? Acabou escolhendo python e está ganhando tração com a solução nas mãos de clientes reais. Esse é o verdadeiro custo da otimização prematura: custo de oportunidade.

Uso de Recursos

Uma coisa em que Python é genuinamente ineficiente é uso de recursos. Objetos Python têm mais overhead, e o garbage collector mantém referências por mais tempo que gerenciamento manual de memória faria.

Podemos ver isso no exemplo da Lovable - eles foram de 200 instâncias de servidor pra apenas 10 quando migraram de Python pra Go. Isso é uma redução de 20x nos custos de infraestrutura. Os tempos de deployment caíram de 15 minutos pra 3 minutos, e tempos médios de request melhoraram em 12%.

Mas aqui está o contexto-chave: a Lovable estava lidando com 50+ requests concorrentes por request de chat com paralelismo pesado. Essa não é uma workload típica de AI SaaS - a maioria das startups estão fazendo chamadas sequenciais de API pra OpenAI, não orquestrando dúzias de operações paralelas. Para a maioria das aplicações SaaS de IA, eficiência de recursos não importa muito até você ser grande. Realmente grande.

Suas chamadas de API pra OpenAI não ligam se seu servidor web usa 100MB ou 500MB de RAM. Seu banco de dados não roda mais rápido porque seu servidor de API tem menor uso de memória. Se você está fazendo 1000 requests por dia, a diferença entre rodar 1 instância de servidor vs 2 é talvez R$100/mês - não exatamente algo que mata sua startup.

O que realmente restringe recursos em AI SaaS típico:

  • Rate-limit de API: Bata no limite de rate da OpenAI e seus usuários ficam esperando independentemente de quão eficiente é seu uso de memória.
  • Conexões de banco de dados: Ficar sem slots da sua connection pool vai matar a performance. Isso não tem nada a ver com sua linguagem de programação.
  • Largura de banda do desenvolvedor: O recurso mais caro numa startup. Gastar 3 meses otimizando uso de memória enquanto concorrentes entregam features é o verdadeiro desperdício.
  • Tokens de IA: Você está pagando caro por tokens OpenAI/Claude, não RAM do servidor.

Os principais aprendizados da migração da Lovable: eles chegaram a quase uma avaliação de $2 bilhões com Python antes de ter que mudar. Eles sabiam exatamente o que precisavam otimizar e por quê - padrões específicos de concorrência que estavam causando dor operacional real. Eles mediram melhorias concretas: velocidade de deployment, performance de request, custos de infraestrutura.

Essa é um exemplo de otimização baseada em restrições reais, não otimização prematura baseada em preocupações teóricas de performance.

A maioria das startups de IA nunca vai atingir a escala onde o uso de recursos do Python se torna o gargalo. E se você atingir essa escala, parabéns - você tem um negócio de sucesso e pode contratar engenheiros pra otimizar as partes que realmente importam.

Resumo

A lentidão do Python e maior uso de recursos são reais. Mas para SaaS de IA que gastam 99% do seu tempo esperando por APIs externas e bancos de dados, essas limitações não importam.

O caminho pro sucesso não é escolher a linguagem "mais rápida" - é entender suas restrições reais e otimizar o que importa. Construa seu MVP em Python. Meça onde estão os verdadeiros gargalos. Arrume esses gargalos primeiro. Quando você bater nos limites reais do Python (não teóricos), aí considere alternativas.

O CEO que mencionei? Sua startup entregou o MVP em Python e agora está ganhando tração com clientes. Enquanto isso, seus concorrentes que escolheram Rust por "razões de performance" sem realmente precisar podem ainda estar reescrevendo handlers HTTP.

Engenharia de software é sobre tradeoffs, não tendências. Tome decisões baseadas nas suas restrições reais, não em posts de benchmark. Seus usuários não ligam se seu backend roda em Python ou Rust. Eles ligam se seu produto resolve os problemas deles.

Artigo escrito originalmente em inglês no blog do FastroAI e traduzido com ajuda de IA pra postar aqui


Quer pular meses de setup e entregar seu SaaS de IA hoje? Confira o FastroAI - um template FastAPI pronto pra produção com autenticação, pagamentos, integração de IA, e tudo mais que você precisa pra lançar. Pare de construir infraestrutura, comece a construir soluções.

Carregando publicação patrocinada...
8

Certa vez eu vi um exemplo de um palestrante que eu achei bastante pertinente quando se fala em comparar velocidades das linguagens.

Era algo mais ou menos como: "Benchmarks de linguagens de programação são como Fórmula 1, quem chega mais rápido em um ambiente controlado e competitivo, mas a vida real dos programas que desenvolvemos está mais próximo de um rally. Um carro de rally vai conseguir andar muito bem em uma pista de Fórmula 1, mas um carro de Fórmula 1 praticamente não sai do lugar no ambiente de rally".

Acredito que vale muito a pena sacrificar um pouco de desempenho em troca de flexibilidade e funcionalidades, Rust é ótimo para o propósito que se propõe, mas só por ser rápido não significa ser a melhor opção que Python, JS, Ruby e etc nos casos em que essas linguagens já atuam bem.

0
3

Só queria fazer uma observação sobre Python, sobre a vantagem da maior legibilidade e facilidade/velocidade de prototipação. O criador do Numpy disse que usava Perl na década de 90. Mas quando ficava meses sem mexer no código, quando voltava não conseguia lembrar o que tinha feito ou porque tinha codificado daquele jeito. Então migrou pro Python e tudo ficou mais fácil.

Esse ano to programando em C++, porque achei Rust muito chato. Tem que levar em consideração também o prazer de programar, além de tudo que foi mencionado acima.

2
2

Boa, eu amo python, amo digitar cada linha de código em python e concordo plenamente que o prazer de se programar em determinada lang é o ponto crucial que nos mantém fiéis a ela.

2

Veja só, 3% não é nada desprezível, né? E não quer dizer que o seu sistema seja 3% em pontos que precisam de performance, pode ser quase 100%, ou pode ser virtualmente 0%. A maioria das pessoas não entendem essa frase.

É claro que se a arquitetura é toda errada, passa por muitas camadas, depende de serviços que podem te colocar em fila, estar fora do ar e tem outros problemas, a performance não costuma ser importante, é como colocar um chiclete em um balde para fechar um buraquinho e o balde está todo arrebentado e vaza água pra todo lado.

Tem casos que nem deveria ser web. Aí você otimizar para que? Tem sistemas que exigem algo que a maioria das pessoas, especialmente mais novas, precisa de coisas que não ten "ninguém" estudando.

O meu resumo é o mesmo que do artigo original:

A lentidão do Python e maior uso de recursos são reais. Mas para SaaS de IA que gastam 99% do seu tempo esperando por APIs externas e bancos de dados, essas limitações não importam.

Mas tem muitos casos que o sistema é bem arquitetado e precisa de uma tecnologia que entrega mais. Em alguns casos não é nem sobre performance, é sobre robustez e manutibilidade.

S2


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui no perfil também).

1

Certamente, a ideia aqui é mais usar isso como tema pra fazer as pessoas pensarem mais em tradeoffs que em "A é melhor que B". Se é pra tomar decisões, é bom pelo menos ter base.

1

Sinceramente, não sou muito fã de Rust e só migraria para ela se não existisse C++, pois já sei programar em C. Para mim, Rust e suas "proteções" são desnecessárias, porque é fácil corrigir esses problemas em C e C++.

Gosto bastante de Python e concordo com muito do que você disse, principalmente porque muitas aplicações sendo implementadas nem precisam tanto de velocidade para funcionar. Infelizmente, tenho críticas ao seu primeiro exemplo, porque a concorrência do Go é incrível. Tente fazer um projeto no estilo "jantar dos filósofos" em Go e você conseguirá ver como ele funciona. Desenvolvi esse projeto em Go, Python e C (projeto da 42), e nossa, como Go consegue organizar tudo certinho e elegantemente, colocando cada processo em seu lugar sem problema algum e com velocidade surpreendente.

Acredito que isso varia caso a caso. Se for para ter um SaaS bem estruturado e escalável, focado em grande público, Go certamente deve ser a opção. Se você está querendo um SaaS sem ter certeza e não quer enfrentar a dificuldade de aprender uma nova sintaxe (apesar de considerar a sintaxe do Go bastante simples e intuitiva), então opte por Python. Em geral, para a maioria dos serviços que vi na web, usar Go ou Python não fará tanta diferença. Agora, se o serviço demanda velocidade ou possui uma quantidade expressiva de usuários, Go tem que ser a escolha, pela forma como organiza todas as informações mantendo um custo de processamento extremamente baixo.

1