- O gerenciador de pacotes Python uv mostra uma velocidade de instalação mais de 10 vezes maior que a do pip, e isso não acontece simplesmente por ter sido escrito em Rust, mas por escolhas de design
- O ponto central que tornou essa velocidade possível são os padrões de metadados estáticos (PEP 518, 517, 621, 658), que permitem identificar dependências sem executar código
- O uv removeu de forma ousada funcionalidades legadas mantidas pelo pip (.egg, pip.conf, instalação no Python do sistema etc.), eliminando caminhos de código desnecessários
- A contribuição do Rust está em pontos como desserialização zero-copy, concorrência sem locks e estrutura de binário único, ocupando apenas parte do ganho total de desempenho
- No geral, o caso do uv mostra que metadados padronizados e a remoção de compatibilidades desnecessárias são o núcleo da inovação em performance
Os padrões que possibilitaram a velocidade do uv
- A lentidão do pip não vem de um problema de implementação, mas da antiga estrutura baseada em setup.py, na qual era preciso executar código para descobrir as dependências
- Executar
setup.py exigia instalar dependências de build, o que causava um "problema do ovo e da galinha"
- Durante a instalação, havia execução arbitrária de código e falhas repetidas, reduzindo a velocidade do processo
- O PEP 518 (2016) introduziu o
pyproject.toml, permitindo declarar dependências de build sem executar código
- O PEP 517 (2017) separou frontend e backend de build, eliminando a necessidade de o pip entender os detalhes internos do setuptools
- O PEP 621 (2020) padronizou a tabela
[project], permitindo verificar dependências apenas com parsing de TOML
- O PEP 658 (2022) passou a incluir os metadados do pacote diretamente na Simple Repository API, permitindo obter informações de dependência sem baixar a wheel
- O PyPI aplicou o PEP 658 em maio de 2023, e o uv foi lançado em fevereiro de 2024, surgindo como a primeira ferramenta a aproveitar completamente a nova infraestrutura padronizada
- Assim como o Cargo do Rust e o npm, o ecossistema Python agora também está migrando para um empacotamento baseado em metadados estáticos
Funcionalidades que o uv removeu
- A velocidade do uv vem da remoção de recursos desnecessários
- Sem suporte a
.egg: o pip ainda processa isso, mas o uv exclui completamente
- Ignora
pip.conf: arquivos de configuração, variáveis de ambiente e lógica de herança são todos omitidos
- Compilação de bytecode desativada: não converte
.py em .pyc, reduzindo o tempo de instalação
- Ambiente virtual obrigatório: como não instala diretamente no Python do sistema, elimina verificações de permissão e código de segurança
- Conformidade estrita com a especificação: rejeita pacotes inválidos, reduzindo a lógica de tratamento de exceções
- Ignora limites superiores de
requires-python: restrições defensivas como python<4.0 são ignoradas, reduzindo o backtracking na resolução de dependências
- Prioridade para o primeiro índice: ao encontrar o pacote no primeiro entre vários índices, para imediatamente, evitando ataques de confusão de dependência e reduzindo requisições de rede
- Todos esses itens são exemplos de caminhos de código que o pip precisa manter e que o uv simplesmente elimina
Otimizações possíveis sem Rust
- Uma parte considerável da velocidade do uv vem de otimizações de design independentes da linguagem
- Requisições HTTP Range para baixar apenas parcialmente o diretório central de arquivos wheel, evitando o download completo
- Downloads em paralelo para buscar vários pacotes ao mesmo tempo
- Uso de cache global e hardlinks, de modo que instalar o mesmo pacote em vários ambientes virtuais não consome espaço extra em disco
- Resolução independente de Python: faz parsing direto de TOML e dos metadados das wheels, executando Python apenas quando existe somente
setup.py
- Uso do algoritmo de resolução de dependências PubGrub, mais rápido que o método de backtracking do pip e com explicações de erro mais claras
Onde o Rust realmente contribuiu
- O Rust tem um papel importante em otimizações específicas de baixo nível
- Desserialização zero-copy com base em rkyv, permitindo usar dados de cache diretamente, sem cópia
- Estruturas de concorrência sem locks para acesso paralelo com segurança
- Sem inicialização de interpretador: o uv é um binário estático único, eliminando o custo de criar um processo Python como no pip
- Representação compactada de informações de versão em inteiros
u64, acelerando comparações e operações de hash
- Esses elementos melhoram o desempenho, mas não são a causa principal do ganho total de velocidade
Lição principal
- A velocidade do uv não vem do Rust, mas das coisas que ele deixa de fazer
- A padronização dos PEPs 518, 517, 621 e 658 criou a base para um gerenciamento de pacotes rápido, e o uv concretizou isso com remoção de legado e premissas modernas
- O pip até poderia implementar downloads em paralelo, cache global e resolução baseada em metadados, mas 15 anos de manutenção de compatibilidade retroativa são um obstáculo
- Como resultado, o pip tende a continuar lento, e só ferramentas que partem de novas premissas conseguem melhorias fundamentais de velocidade
- A lição para outros gerenciadores de pacotes é que metadados estáticos, descoberta de dependências sem execução de código e uma estrutura resolvível antecipadamente são essenciais
- Cargo e npm já adotam esse modelo, e ecossistemas que precisam executar código para verificar dependências são, na raiz, mais lentos
1 comentários
Comentários do Hacker News
Acho que este texto explicou muito bem a performance do uv por vários ângulos
O fato de ter sido escrito em Rust ajuda, mas o que teve um papel muito maior foi o esforço de padronização que, ao longo dos últimos 10 anos, fez o ecossistema Python sair da dependência de
setup.pyRust também pode ser uma boa escolha por um motivo parecido, já que tende a elevar o nível da comunidade
Dá para revisitar os erros do passado e criar um design melhor, somando isso às vantagens da própria linguagem, quase como um “golpe duplo”
Concordo com a ideia de que “o uv não é rápido porque é Rust, mas porque há muitas coisas que ele não faz”
Ainda assim, acho cedo cravar os fatores de velocidade sem benchmarks
O impacto das PEP 518, 517, 621 e 658 é grande, mas fico em dúvida sobre quanto a remoção de compatibilidade realmente contribuiu
Também não se discute que efeito a escolha da linguagem teve nas otimizações
O fato de o parser TOML do Cargo ser muito mais rápido que o do Python também é interessante
Na prática, o TOML só é lido na etapa de build, então seu peso não é tão grande, mas a popularização dos wheels contribuiu para o ganho de velocidade
Leitura relacionada: setup.py deprecated, wheels are faster
A desserialização zero-copy com
rkyvnão é uma técnica exclusiva de RustTambém é possível em linguagens de baixo nível como C/C++
A observação sobre “não haver inicialização do interpretador” está no mesmo contexto
O conteúdo do texto é bom, mas o estilo lapidado por LLM parece artificial demais
Talvez um dia chegue a época em que teremos de restaurar textos danificados por LLM para que voltem a soar humanos
Parece ser um especialista em segurança da cadeia de suprimentos, mas aquele texto também dava a sensação de ter sido contaminado por um estilo vago típico de LLM
Esses prompts fixos acabam deixando tudo com a mesma cara, e é uma pena que a internet esteja começando a soar como se tivesse uma voz única
Não entendo muito bem o entusiasmo com a velocidade do uv
Acho que, para a maioria dos usuários de Python, a velocidade de instalação de pacotes nem entraria no top 10 das preocupações
Eu também uso Python todos os dias, mas quase não sinto diferença
poetrylevava de 5 a 30 minutosSe falhasse, era preciso esperar mais 30 minutos, então o uv foi realmente uma experiência muito mais agradável
pip installocupava uma parte grande do tempo de deployPassei muito tempo tentando acelerar isso com caching
poetry installleva 2 minutos, enquantouv synctermina em poucos segundosEconomizar 2 minutos em cada CI gera um efeito acumulado grande
uvx sometool, a criação do ambiente virtual e a instalação das dependências terminam em segundos, o que mudou completamente meu fluxo de trabalhoAgora é difícil voltar para projetos sem uv
Algumas técnicas de otimização de velocidade do uv parecem portáveis para o pip
Por exemplo: downloads paralelos, geração adiada de
.pyc, ignorar eggs, verificação de versão etc.Mas o uv lida tão bem com venv que talvez nem valha a pena mexer no pip
No fim, a questão é que não é “só por causa do Rust”, então o pip também ainda tem espaço para ficar mais rápido
Programadores que escolhem uma linguagem rápida muitas vezes já têm uma mentalidade voltada para otimização de performance
Mais do que a linguagem em si, é essa atitude que costuma determinar o desempenho
É interessante o motivo de o uv ignorar o limite superior
python<4.0A maioria dos pacotes definiu isso de forma defensiva, por medo de quebrar no Python 4, quando na prática provavelmente funcionariam sem problemas
Essas restrições superiores eram uma tentativa de resolver um problema hipotético, e não algo real
Restrições como
python<3.0continuam sendo importantes, então nesses casos o bloqueio deve permanecerNão é coincidência que a PEP 658 tenha sido adotada em 2023 e o uv tenha surgido em 2024
O ecossistema ficou pronto, e foi isso que tornou possível uma ferramenta como o uv
Mas fico curioso sobre por que os mantenedores de pacotes aceitaram esse tipo de mudança
Muita gente devia achar que
setup.pyjá funcionava bem, então qual foi a motivação para migrar para pyproject.toml?setup.pyjá era incômodo para muita gentePor exemplo, nem o Requests ainda tem compatibilidade completa com PEP 517/518/621
Mesmo depois de um ano e meio, uma minor release segue atrasada, e nesse meio-tempo também houve problemas de build
Ainda assim, é curioso por que o pip não aproveita isso melhor
A frase “não é preciso esperar por caminhos de código que não existem” não é muito precisa
Só economiza tempo o código que realmente deixa de ser executado
Por exemplo, não ter suporte a
.eggnão afeta a velocidade se já for um formato obsoletoSeria melhor se houvesse dados quantitativos mostrando quanto cada item realmente economizou de tempo
Ainda assim, no geral, o texto está bem organizado