- Analyse der Leistungsgrenzen von Bundler und Vergleich mit den Gründen, warum der Python-Paketmanager uv so schnell ist
- Die Geschwindigkeit von uv beruht nicht auf Rust selbst, sondern auf strukturellen Designentscheidungen wie parallelen Downloads, globalem Cache und metadatenbasierter Abhängigkeitsverarbeitung
- Bei Bundler sind Download und Installation gekoppelt, was die Parallelisierung einschränkt; eine Trennung verspricht deutliche Verbesserungen
- Durch Integration eines globalen Caches, Installation per Hardlink und Einbindung des PubGrub-Solvers ließen sich Doppelungen zwischen RubyGems und Bundler reduzieren
- Auch ohne Neuschreibung in einer anderen Sprache lassen sich die meisten Performance-Verbesserungen direkt in Ruby erreichen, sodass eine Geschwindigkeit nahe uv möglich ist
Leistungsvergleich von Bundler und uv
- Ausgehend von der auf der RailsWorld gestellten Frage „Warum ist Bundler nicht so schnell wie uv?“ werden die Performance-Engpässe von Bundler untersucht
- Der Autor ist überzeugt, dass Bundler Geschwindigkeiten auf uv-Niveau erreichen kann, und stellt klar, dass der Unterschied nicht an der Sprache, sondern am Design liegt
- Unter Bezug auf Andrew Nesbitts Artikel „How uv got so fast“ wird analysiert, ob sich die zentralen Optimierungen von uv auf Bundler übertragen lassen
Neuschreibung in Rust?
- Zwar ist uv in Rust geschrieben, doch die eigentliche Ursache für die Geschwindigkeit ist nicht Rust selbst
- Wenn das Beseitigen der Engpässe in Bundler dazu führt, dass „eine Neuschreibung in Rust die einzig verbleibende Verbesserung“ wäre, dann wäre das bereits ein Erfolg
- Eine Neuschreibung in Rust bietet die Freiheit, experimentelle Designs ohne bestehende Kompatibilitätszwänge auszuprobieren, ist aber keine zwingende Voraussetzung
Strukturelle Engpässe in Bundler
- Bundler koppelt den Download und die Installation von Gems in einer einzigen Methode, wodurch parallele Downloads unmöglich werden
- Im Beispielcode führt die Methode
install nacheinander fetch_gem_if_not_cached und install aus
- Dadurch können Gems mit Abhängigkeiten (
a -> b -> c) nur sequentiell installiert werden
- Experimente zeigen: Mit Abhängigkeiten dauert es über 9 Sekunden, während unabhängige Gems (
d, e, f) per parallelem Download in weniger als 4 Sekunden abgeschlossen sind
- Durch eine Trennung von Download und Installation ließe sich parallel arbeiten, ohne die Abhängigkeitsregeln zu verletzen
- Vorgeschlagen wird eine Aufteilung in vier Schritte (Download → Entpacken → Kompilieren → Installation)
- Bei reinen Ruby-Gems könnte die Installationsreihenfolge der Abhängigkeiten gelockert werden, was zusätzlichen Geschwindigkeitsschub bringen würde
Cache- und Installationsoptimierung
- Das Modell von uv mit globalem Cache und Installation per Hardlink ließe sich auch auf Bundler anwenden
- Bundler und RubyGems verwenden derzeit getrennte Caches je Ruby-Version
- Erforderlich wäre eine Zusammenführung in einen gemeinsamen Cache auf Basis von
$XDG_CACHE_HOME
- Die Installation per Hardlink wäre nach einer solchen Cache-Zusammenführung möglich
- Bundler nutzt bereits den Abhängigkeits-Solver PubGrub, während RubyGems weiterhin molinillo verwendet
- Eine Vereinheitlichung der Solver beider Systeme ist zentral für den Abbau technischer Schulden
Übertragbarkeit Rust-bezogener Optimierungen
- Zero-copy-Deserialisierung könnte teilweise auch beim YAML-Parsing in RubyGems angewendet werden
- Der GVL (Global VM Lock) von Ruby schränkt Parallelisierung bei IO-lastigen Aufgaben nicht stark ein
- IO- und ZLIB-Verarbeitung geben den GVL frei, sodass parallele Ausführung möglich ist
- Beim Schreiben kleiner Dateien kann allerdings der Overhead der GVL-Verwaltung die Leistung mindern
- An Verbesserungen innerhalb von Ruby wird bereits gearbeitet
- Optimierung von Versionsvergleichen: uv kodiert Versionen als
u64-Integer, um Vergleiche zu beschleunigen
- Auch in Ruby ließe sich
Gem::Version in eine integerbasierte Darstellung überführen, um die Solver-Performance zu verbessern
- Entsprechende Refactoring-Versuche gab es bereits, wurden aber wegen Abwärtskompatibilitätsproblemen aufgeschoben
Fazit und weitere Pläne
- Die Geschwindigkeit von uv beruht eher auf einem Design, das unnötige Arbeit vermeidet, als auf der Sprache selbst; Bundler kann in dieselbe Richtung verbessert werden
- RubyGems und Bundler verfügen bereits über eine moderne Paketverwaltungsstruktur, sodass Geschwindigkeiten auf uv-Niveau realistisch sind
- Die größte Herausforderung bleibt Legacy-Code und die Wahrung der Kompatibilität
- Auch ohne Neuschreibung in Rust sind 99 % der Performance-Gewinne innerhalb des Ruby-Codes erreichbar; das verbleibende 1 % fällt kaum ins Gewicht
- In einem Folgebeitrag sollen das tatsächliche Profiling von Bundler und RubyGems sowie die konkreten Ursachen der Engpässe behandelt werden
Noch keine Kommentare.