17 points par GN⁺ 2025-12-27 | 1 commentaires | Partager sur WhatsApp
  • Le gestionnaire de paquets Python uv offre une vitesse d’installation plus de 10 fois supérieure à celle de pip, non pas simplement parce qu’il est écrit en Rust, mais grâce à des choix de conception
  • L’élément clé qui rend cette vitesse possible est l’existence de standards de métadonnées statiques (PEP 518, 517, 621, 658), qui permettent d’identifier les dépendances sans exécuter de code
  • uv supprime sans hésiter des fonctions legacy conservées par pip (.egg, pip.conf, installation sur le Python système, etc.), ce qui élimine les chemins de code inutiles
  • La contribution de Rust tient à des éléments comme la désérialisation zero-copy, la concurrence sans verrou et une architecture en binaire unique, mais cela ne représente qu’une partie du gain global de performance
  • Dans l’ensemble, le cas uv montre que la standardisation des métadonnées et la suppression des compatibilités inutiles sont au cœur de l’innovation en matière de performances

Les standards qui ont rendu possible la rapidité de uv

  • La lenteur de pip ne vient pas d’un problème d’implémentation, mais de son ancienne architecture fondée sur setup.py, qui obligeait à exécuter du code pour connaître les dépendances
    • L’exécution de setup.py exigeait l’installation de dépendances de build, créant ainsi un « problème de l’œuf et de la poule »
    • Le processus d’installation entraînait l’exécution de code arbitraire et des échecs répétés, ce qui ralentissait l’installation
  • PEP 518 (2016) a introduit pyproject.toml, permettant de déclarer les dépendances de build sans exécuter de code
  • PEP 517 (2017) a séparé le frontend de build du backend, évitant à pip d’avoir à comprendre l’intérieur de setuptools
  • PEP 621 (2020) a standardisé la table [project], rendant possible la vérification des dépendances via un simple parsing TOML
  • PEP 658 (2022) a intégré les métadonnées des paquets directement dans la Simple Repository API, permettant de récupérer les informations de dépendances sans télécharger les wheels
  • PyPI a appliqué PEP 658 en mai 2023, et uv, lancé en février 2024, est apparu comme le premier outil à exploiter pleinement cette nouvelle infrastructure standardisée
  • Comme Cargo en Rust ou npm, l’écosystème Python bascule désormais lui aussi vers un packaging fondé sur des métadonnées statiques

Les fonctions supprimées par uv

  • La rapidité de uv vient de la suppression de fonctions inutiles
    • Pas de prise en charge de .egg : pip continue de les gérer, uv les exclut totalement
    • pip.conf ignoré : les fichiers de configuration, variables d’environnement et logiques d’héritage sont tous omis
    • Compilation du bytecode désactivée : les fichiers .py ne sont pas convertis en .pyc, ce qui réduit le temps d’installation
    • Environnement virtuel obligatoire : pas d’installation directe sur le Python système, ce qui supprime les vérifications de permissions et le code de sécurité associé
    • Respect strict des spécifications : les paquets incorrects sont rejetés, ce qui réduit la logique de gestion des exceptions
    • Ignorance de la borne supérieure de requires-python : des contraintes défensives comme python<4.0 sont ignorées, ce qui réduit la résolution de dépendances par backtracking
    • Priorité au premier index : si le paquet est trouvé sur le premier index parmi plusieurs, uv s’arrête immédiatement, ce qui évite les attaques de confusion de dépendances et réduit les requêtes réseau
  • Tous ces points illustrent des chemins de code que pip doit encore exécuter, mais que uv a éliminés

Optimisations possibles sans Rust

  • Une grande partie de la rapidité de uv vient d’optimisations de conception indépendantes du langage
    • Requêtes HTTP Range pour ne télécharger que le répertoire central des fichiers wheel, en évitant le téléchargement complet
    • Téléchargements parallèles pour récupérer plusieurs paquets en même temps
    • Cache global et liens physiques permettant d’installer le même paquet dans plusieurs environnements virtuels sans consommation supplémentaire d’espace disque
    • Résolution indépendante de Python : parsing direct du TOML et des métadonnées wheel, avec exécution de Python seulement lorsqu’il n’existe qu’un setup.py
    • Utilisation de l’algorithme de résolution de dépendances PubGrub, plus rapide que l’approche par backtracking de pip et offrant des erreurs plus explicites

Ce que Rust a réellement apporté

  • Rust joue un rôle important dans certaines optimisations bas niveau
    • Désérialisation zero-copy basée sur rkyv pour utiliser directement les données du cache sans copie
    • Structures de concurrence sans verrou pour permettre un accès parallèle sûr
    • Pas d’initialisation d’interpréteur : uv est un binaire statique unique, ce qui supprime le coût de création d’un processus Python comme avec pip
    • Représentation compacte des versions en entiers u64, pour accélérer les comparaisons et les opérations de hachage
  • Ces éléments améliorent les performances, mais ne sont pas la cause principale du gain global de vitesse

Enseignement clé

  • La rapidité de uv ne vient pas de Rust, mais de tout ce qu’il choisit de ne pas faire
  • La standardisation portée par PEP 518, 517, 621 et 658 a posé les bases d’une gestion rapide des paquets, et uv l’a concrétisée grâce à la suppression du legacy et à des hypothèses modernes
  • pip pourrait lui aussi implémenter les téléchargements parallèles, le cache global et une résolution fondée sur les métadonnées, mais 15 ans de maintien de la compatibilité descendante constituent un frein majeur
  • En conséquence, pip est condamné à rester lent, et seuls les outils conçus sur de nouvelles hypothèses peuvent apporter un gain de vitesse fondamental
  • La leçon pour les autres gestionnaires de paquets est qu’une architecture fondée sur des métadonnées statiques, l’exploration des dépendances sans exécution de code et la possibilité d’une résolution préalable est indispensable
  • Cargo et npm ont déjà adopté cette approche, et tout écosystème qui doit exécuter du code pour vérifier les dépendances est fondamentalement lent

1 commentaires

 
GN⁺ 2025-12-27
Réactions sur Hacker News
  • Je trouve que cet article explique très bien les performances de uv sous plusieurs angles
    Le fait qu’il soit écrit en Rust aide, mais les efforts de standardisation menés ces dix dernières années pour faire sortir l’écosystème Python de la dépendance à setup.py ont joué un rôle bien plus important

    • Quand je travaillais autrefois sur des projets Haskell, l’un des avantages n’était pas tant le langage lui-même que le fait de pouvoir sélectionner une communauté d’experts
      Rust peut être choisi pour une raison similaire, en tirant le niveau de la communauté vers le haut
    • Beaucoup de projets de réécriture en Rust bénéficient de cet effet de halo
      Ils peuvent corriger les tâtonnements du passé avec une meilleure conception, tout en ajoutant les avantages propres à Rust, ce qui forme une sorte de « double effet »
  • Je suis d’accord avec l’idée que « uv n’est pas rapide parce qu’il est en Rust, mais parce qu’il y a beaucoup de choses qu’il ne fait pas »
    Cela dit, sans benchmark, il est encore trop tôt pour trancher sur les causes exactes de cette vitesse
    L’impact des PEP 518, 517, 621 et 658 est important, mais je me demande dans quelle mesure la suppression de compatibilité y contribue réellement
    On ne parle pas non plus de l’influence du choix du langage sur les optimisations possibles
    Le fait que le parseur TOML de Cargo soit bien plus rapide que celui de Python est aussi intéressant

    • Comparer les anciennes versions de pip aux versions actuelles pourrait aussi constituer une forme de benchmark
      En pratique, TOML n’est lu qu’au moment du build, donc son poids reste limité, mais la généralisation des wheel a contribué aux gains de vitesse
      Références associées : setup.py deprecated, wheels are faster
  • La désérialisation zero-copy avec rkyv n’est pas une technique propre à Rust
    C’est aussi possible dans des langages bas niveau comme le C/C++

    • Ici, je comprends « réservé à Rust » au sens de « impossible en Python »
      L’idée qu’« il n’y a pas de démarrage d’interpréteur » va dans le même sens
    • Comme il est difficile d’implémenter le zero-copy en Python, je reconnais que Rust le rend sûr et simple
    • Au fond, ce débat revient à comparer Rust et Python
  • Le fond de l’article est bon, mais le style retravaillé par un LLM paraît trop artificiel
    Peut-être qu’un jour, à cause des LLM, on devra restaurer de manière humaine des textes qu’ils auront dénaturés

    • L’auteur est aussi déjà apparu sur HN avec des billets sur les SBOM et les lockfiles
      Il semble être un spécialiste de la sécurité de la supply chain, mais ces textes aussi donnaient l’impression d’être déformés par le style vague typique des LLM
    • À l’inverse, certains n’y ont senti aucune trace de LLM et ont trouvé le texte naturel
    • Moi, dès que je sens une odeur d’IA dans un texte, je ferme l’onglet
      Des prompts figés finissent par rendre tous les textes semblables, et je trouve dommage qu’Internet sonne comme une seule et même voix
  • Je ne comprends pas vraiment l’enthousiasme autour de la vitesse de uv
    La plupart des utilisateurs de Python ne mettraient sans doute pas la vitesse d’installation des paquets dans leur top 10 des préoccupations
    J’utilise moi-même Python tous les jours et je ne ressens pas un tel impact

    • Dans mon ancienne entreprise, les mises à jour de dépendances avec poetry prenaient entre 5 et 30 minutes
      Et en cas d’échec, il fallait parfois attendre encore 30 minutes, donc uv était vraiment une expérience très agréable
    • J’utilise Python depuis plus de 20 ans, et pip install représentait souvent une part importante du temps de déploiement
      J’ai passé beaucoup de temps à essayer d’accélérer ça avec du caching
    • Dans mon application monolithique interne, poetry install prend 2 minutes, alors que uv sync se termine en quelques secondes
      Économiser 2 minutes sur chaque CI finit par avoir un gros effet cumulé
    • Même quand j’exécute uvx sometool, la création de l’environnement virtuel et l’installation des dépendances ne prennent que quelques secondes, ce qui change complètement le flux de travail
    • En tant qu’utilisateur Python de longue date, la vitesse de uv est du niveau changement de qualité de vie
      Il devient difficile de revenir à des projets sans uv
  • Certaines techniques d’optimisation de vitesse de uv semblent pouvoir être portées dans pip
    Par exemple : téléchargements parallèles, génération différée des .pyc, ignorance des egg, vérifications de version, etc.
    Mais uv gère tellement bien les venv qu’il n’y a sans doute pas vraiment besoin de retoucher pip
    Au final, cela montre surtout que ce n’est pas « uniquement grâce à Rust » et que pip a lui aussi une marge d’accélération

  • Les programmeurs qui choisissent un langage rapide ont souvent déjà un état d’esprit orienté optimisation des performances
    Plus que le langage lui-même, c’est cette attitude qui détermine souvent les performances

  • Il est intéressant de voir pourquoi uv ignore la borne haute python<4.0
    La plupart des paquets l’ont définie de manière défensive, par crainte qu’ils cassent avec Python 4, alors qu’en pratique ce n’est souvent pas le cas
    Ces bornes supérieures cherchaient à résoudre des problèmes hypothétiques plutôt que des problèmes réels

    • Il semble que uv n’ignore pas toutes les bornes supérieures, mais seulement celles liées à 4.0
      Des contraintes comme python<3.0 restent importantes, donc il faut continuer à les bloquer dans ces cas-là
  • Le fait que la PEP 658 ait été appliquée en 2023 et que uv soit apparu en 2024 n’a rien d’un hasard
    L’écosystème était prêt, ce qui a rendu possible un outil comme uv
    Mais je me demande pourquoi les mainteneurs de paquets ont accepté ce changement
    Même si setup.py fonctionnait bien pour certains, qu’est-ce qui les a motivés à passer à pyproject.toml ?

    • En réalité, setup.py était contraignant pour beaucoup de monde
      Par exemple, même Requests n’est toujours pas entièrement compatible avec les PEP 517/518/621
      Un an et demi plus tard, une release mineure est toujours retardée, et entre-temps il y a aussi eu des problèmes de build
    • Les déclarations statiques étaient plus sûres et meilleures pour les performances
      En revanche, on peut se demander pourquoi pip n’en tire pas suffisamment parti
  • La formule « les chemins de code qu’on ne prend pas n’ont pas à attendre » est imprécise
    Seul le code qui n’est pas exécuté fait réellement gagner du temps
    Par exemple, ne pas prendre en charge les .egg n’a aucun impact sur la vitesse s’il s’agit déjà d’un format abandonné
    Il aurait été préférable d’avoir des données quantitatives sur le temps réellement économisé par chaque élément
    Malgré cela, l’article reste globalement bien structuré