- Bundler’ın performans sınırları analiz ediliyor ve Python paket yöneticisi uv’nin neden hızlı olduğu karşılaştırılıyor
- uv’nin hızı Rust dilinden değil; paralel indirme, global önbellek, metadata tabanlı bağımlılık işleme gibi yapısal tasarım tercihlerinden kaynaklanıyor
- Bundler’da indirme ve kurulum süreci birbirine bağlı olduğu için paralel işlem kısıtlanıyor; bunların ayrılması büyük iyileştirme sağlayabilir
- Global önbellek entegrasyonu, hardlink ile kurulum, PubGrub çözücüsünün entegrasyonu gibi adımlarla RubyGems ve Bundler arasındaki tekrar azaltılabilir
- Dili yeniden yazmadan da performans artışının büyük kısmı Ruby kodu içinde elde edilebilir ve uv seviyesine yakın hızlara ulaşılabilir
Bundler ve uv performans karşılaştırması
- RailsWorld’de sorulan “Bundler neden uv kadar hızlı değil?” sorusundan yola çıkılarak Bundler’ın performans darboğazları inceleniyor
- Yazar, Bundler’ın uv seviyesinde hıza ulaşabileceğine inandığını ve performans farkının dilden değil tasarımdan kaynaklandığını açıkça belirtiyor
- Andrew Nesbitt’in “How uv got so fast” yazısına atıfla, uv’nin temel optimizasyonlarının Bundler’a uygulanıp uygulanamayacağı analiz ediliyor
Rust’a yeniden yazma meselesi
- uv’nin Rust ile yazılmış olması doğru, ancak hızın asıl nedeni Rust’ın kendisi değil
- Bundler’daki darboğazlar giderilip “geriye kalan tek iyileştirme seçeneği Rust’a yeniden yazmak” olursa, bunun bir başarı sayılacağı belirtiliyor
- Rust’a yeniden yazmak, mevcut uyumluluk kısıtları olmadan deneysel tasarımlar deneme özgürlüğü sunuyor; ancak zorunlu bir koşul değil
Bundler’ın yapısal darboğazları
- Bundler, gem indirme ve kurulumunu tek bir metoda bağladığı için paralel indirme mümkün olmuyor
- Örnek kodda
install metodu, fetch_gem_if_not_cached ve install adımlarını art arda çalıştırıyor
- Bu nedenle bağımlılık ilişkisi olan gem’ler (
a -> b -> c) yalnızca sıralı olarak kurulabiliyor
- Deney sonuçlarına göre bağımlılık olduğunda işlem 9 saniyeden uzun sürerken, bağımsız gem’ler (
d, e, f) paralel indirme ile 4 saniyeden kısa sürede tamamlanıyor
- İndirme ve kurulum ayrılırsa, bağımlılık kuralları korunurken paralel işlem de mümkün hale geliyor
- Dört aşamalı bir ayrım öneriliyor: indirme → arşivden çıkarma → derleme → kurulum
- Saf Ruby gem’lerde bağımlılık kurulum sırası gevşetilerek ek hız kazanımı sağlanabilir
Önbellek ve kurulum optimizasyonu
- uv’nin global önbellek ve hardlink ile kurulum yaklaşımı Bundler’a da uygulanabilir
- Bundler ve RubyGems şu anda Ruby sürümüne göre ayrı önbellekler kullanıyor
$XDG_CACHE_HOME tabanlı paylaşımlı bir önbelleğe geçilmesi gerekiyor
- Hardlink ile kurulum da önbellek birleştirildikten sonra uygulanabilir
- Bundler zaten PubGrub bağımlılık çözücüsünü kullanıyor, ancak RubyGems hâlâ molinillo kullanıyor
- İki sistemin çözücülerinin birleştirilmesi, teknik borcu azaltmanın temel anahtarı olarak görülüyor
Rust bağlantılı optimizasyonların uygulanabilirliği
- Zero-copy deserialization, RubyGems’in YAML ayrıştırma aşamasında kısmen uygulanabilir olabilir
- Ruby’nin GVL’si (Global VM Lock), IO ağırlıklı işlerde paralelliğe büyük bir engel oluşturmuyor
- IO ve ZLIB işlemleri sırasında GVL serbest bırakıldığı için paralel çalışma mümkün
- Ancak küçük dosya yazımlarında GVL yönetim ek yükü performansı düşüren bir etken
- Ruby içinde bunu iyileştirmeye yönelik çalışmalar sürüyor
- Sürüm karşılaştırma optimizasyonu: uv, sürümleri
u64 tamsayısına kodlayarak karşılaştırma hızını artırıyor
- Ruby’de de
Gem::Version değerlerini tamsayı tabanlı yapıya dönüştürerek çözücü performansı artırılabilir
- Bununla ilgili refactoring girişimleri olmuş olsa da geriye dönük uyumluluk sorunları nedeniyle ertelenmiş
Sonuç ve gelecek planları
- uv’nin hızı, dilden çok gereksiz işleri ortadan kaldıran tasarımından geliyor; Bundler da aynı yönde geliştirilebilir
- RubyGems ve Bundler zaten modern bir paket yönetimi yapısına sahip olduğu için, uv seviyesinde hıza ulaşmak gerçekçi görülüyor
- En büyük zorluk eski kod ve uyumluluğun korunması
- Rust’a yeniden yazmadan da performans artışının %99’u Ruby kodu içinde sağlanabilir; kalan %1 ise önemsiz düzeyde
- Devam yazısında Bundler ve RubyGems için gerçek profiling sonuçları ve somut darboğaz nedenleri ele alınacak
2 yorum
Konuşmak ucuz. Kodu göster bana!
Hacker News görüşleri
Bundler’ın yapısını çok iyi bildiğimi söyleyemem ama en büyük iyileşmenin uv’nin önbellek tasarımını benimsemek olacağını düşünüyorum
uv’nin hızlı olmasının temel nedenlerinden biri önbellek yapısı ve bu başka dillerde ya da ekosistemlerde de kopyalanabilir
Ancak
requires-pythonüst sınırını yok sayması performans için değil, daha iyi bir bağımlılık çözümü sağlamak içinÖrneğin bir proje Python 3.8 ve üzerini gerektiriyorsa ama bir bağımlılık
<4kısıtı koyuyorsa, Python 4’te kurulum yapılamazuv tüm desteklenen sürümler için çözüm yaptığı için üst sınırı yok saymanın zaman açısından neredeyse hiçbir kazancı yok
İlgili tartışma Python Discuss forumunda görülebilir
PEP 658’den sonra Python’ın Simple Repository API’si meta veriyi doğrudan sağlıyor; RubyGems.org da zaten benzer bilgileri sunuyor
Ama bir gem’i açmadan native extension içerip içermediğini anlayamıyorsunuz
Bu yüzden bu bilgi doğrudan RubyGems.org meta verisine eklenirse bağımlılık kurulum ağacının tamamen paralelleştirilebileceği öneriliyor
Eskiden RubyGems.org’da çalışırken meta verinin sürüm bazında çıkarıldığını hatırlıyorum
Eski sürümlerin gemspec dosyalarını yeniden işlemek gerekir; bu da riskli bir meta veri değişikliği olabilir
Bu yüzden geçmiş sürümlerde uygulamak zor olabilir ama gelecekte açma işlemi olmadan kurulum sırasını belirlemeyi mümkün kılacak iyileştirmeler yapılabilir gibi görünüyor
Aaron’ın Bundler’ı Rust ile yeniden yazmak yerine gerçek algoritmik iyileştirmelere odaklanmasını seviyorum
Birden fazla sürüm yöneticisi aracı ve Ruby sürümünün birbirine karıştığı bu karmaşık ortam gerçekten çok yorucu
Sorunun sadece hız değil, kontrol ve ekosistemin yönü olduğunu düşünüyorum
Ruby son 10 yılda hıza odaklandı ama belge kalitesi ve topluluk yönetimi aslında daha önemliydi
Dilin neden gerilediğini ciddi biçimde düşünmenin ve farklı fikirleri zorlamanın zamanı geldi
Yakın tarihli ilgili bir yazı olarak How uv got so fast var (Aralık 2025, 457 yorum)
RubyGems’i daha hızlı yapmak için her gem’in dosya listesini kayıt/veritabanı haline getirmek kritik
Böylece her
requireçağrısında dosya sistemini taramak gerekmezBir gem doğrudan değiştirilirse meta veriyi yeniden hash’lemek gerekir ama zaten elle değiştirme tavsiye edilmiyor
Şimdi eski kalmış olabilir ama hâlâ sevdiğim küçük bir proje
Kod: fastup
Asıl sorun,
$LOAD_PATH’in tüm gem’leri ekleyerek kombinatoryal patlama yaratmasıBirden fazla önbellek projesinin var olması bunun gerçek bir problem olduğunun kanıtı
Eskiden bir uygulamanın başlaması dakikalar sürüyordu; load path ile oynayarak bunu dakikalar seviyesinde kısalttığım olmuştu
Zamanında bootsnap’i bundler’a entegre etmeyi önermiştim ama reddedilmişti
RubyGems’in yapısına dair açıklama ilginçti
Gem bir tar dosyası ve içindeki YAML GemSpec bağımlılıkları tanımlıyor
RubyGems.org bu bilgiyi API üzerinden sunduğu için eval kullanmadan da bağımlılıkları kontrol etmek mümkün
Ancak YAML, ayrıştırma açısından verimsiz bir format; JSON ya da protobuf gibi alternatifler daha iyi olabilir
Yine de gemserver zaten bağımlılık bilgisini döndürüyorsa büyük bir sorun olmayabilir
Örneğin yalnızca sürüm, bağımlılıklar ve hash içeren bir yapı
uv’nin hızlı olmasının sebeplerinden biri de bu — paketi indirmeden bağımlılık hesabı yapılabiliyor
Geçmişte gem kurulum yöntemini iyileştiren bir prototip videosu hazırlamıştım
how_gems_should_be.mov
Ruby’nin fibers’ları (veya Async kütüphanesi) çoğu zaman abartılıyor
Thread’lerde olduğu gibi bağlantı havuzu gibi daha üst seviye koordinasyon sorunları yine var
Yine de IO ağırlıklı kurulum işlerini eşzamansız yürütmek anlamlı bir performans artışı sağlayabilir
“Global önbelleğin tüm bundler örnekleri tarafından paylaşılması” fikri değerlendiriliyor
Uzun vadede büyük fayda sağlayabilir gibi görünüyor ama gizli karmaşıklıklar olup olmadığı değerlendiriliyor
İlgili issue: rubygems #7249
Ruby bu sorunu ilk çözen taraf olmayacak, dolayısıyla artık bunun avantajından yararlanma zamanı
Optimizasyonun temel ilkesi basit: Hiçbir şey yapmamak en hızlısıdır
Gerçek optimizasyon, gereksiz işi baştan hiç yapmamaktır