Pourquoi uv est devenu aussi rapide
(nesbitt.io)- 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.pyexigeait 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
- L’exécution de
- 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.confignoré : les fichiers de configuration, variables d’environnement et logiques d’héritage sont tous omis- Compilation du bytecode désactivée : les fichiers
.pyne 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 commepython<4.0sont 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
- Pas de prise en charge de
- 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
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.pyont joué un rôle bien plus importantRust peut être choisi pour une raison similaire, en tirant le niveau de la communauté vers le haut
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
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
rkyvn’est pas une technique propre à RustC’est aussi possible dans des langages bas niveau comme le C/C++
L’idée qu’« il n’y a pas de démarrage d’interpréteur » va dans le même sens
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
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
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
poetryprenaient entre 5 et 30 minutesEt en cas d’échec, il fallait parfois attendre encore 30 minutes, donc uv était vraiment une expérience très agréable
pip installreprésentait souvent une part importante du temps de déploiementJ’ai passé beaucoup de temps à essayer d’accélérer ça avec du caching
poetry installprend 2 minutes, alors queuv syncse termine en quelques secondesÉconomiser 2 minutes sur chaque CI finit par avoir un gros effet cumulé
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 travailIl 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.0La 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
Des contraintes comme
python<3.0restent 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.pyfonctionnait bien pour certains, qu’est-ce qui les a motivés à passer à pyproject.toml ?setup.pyétait contraignant pour beaucoup de mondePar 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
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
.eggn’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é