Scala'ya bakmaya hevesliyim ve cevap bulamadığım tek bir temel sorum var: Genel olarak, Scala ve Java arasında bellek performansı ve kullanımında bir fark var mı?
Scala'ya bakmaya hevesliyim ve cevap bulamadığım tek bir temel sorum var: Genel olarak, Scala ve Java arasında bellek performansı ve kullanımında bir fark var mı?
Yanıtlar:
Scala, farkında olmadan muazzam miktarda belleği kullanmayı çok kolaylaştırır. Bu genellikle çok güçlüdür, ancak bazen sinir bozucu olabilir. Örneğin, bir dizi dizeye (denir array
) ve bu dizelerden dosyalara (denir mapping
) bir haritanız olduğunu varsayalım . Haritada bulunan ve ikiden büyük uzunluktaki dizelerden gelen tüm dosyaları almak istediğinizi varsayalım. Java'da,
int n = 0;
for (String s: array) {
if (s.length > 2 && mapping.containsKey(s)) n++;
}
String[] bigEnough = new String[n];
n = 0;
for (String s: array) {
if (s.length <= 2) continue;
bigEnough[n++] = map.get(s);
}
Whew! Zor iş. Scala'da aynı şeyi yapmanın en kompakt yolu:
val bigEnough = array.filter(_.length > 2).flatMap(mapping.get)
Kolay! Ancak, koleksiyonların nasıl çalıştığına oldukça aşina değilseniz, fark etmeyebileceğiniz şey, bunu yapmanın bu yolunun, dizinin her öğesi (ile , döndüren filter
) için fazladan bir ara dizi (ile ) ve ekstra bir nesne oluşturmasıdır. bir seçenek). Ayrıca, işlev nesneleri küçük olduğu için nadiren büyük bir sorun olsa da, iki işlev nesnesi (biri filtre ve biri flatMap için) oluşturur.mapping.get
Yani, temel olarak, bellek kullanımı, ilkel düzeyde aynıdır. Ancak Scala'nın kütüphaneleri, çok sayıda (genellikle kısa ömürlü) nesneleri kolayca oluşturmanızı sağlayan birçok güçlü yönteme sahiptir. Çöp toplayıcı genellikle bu tür çöplerle oldukça iyidir, ancak hangi belleğin kullanıldığından tamamen habersiz kalırsanız, Scala'da muhtemelen Java'dan daha erken sorun yaşarsınız.
Bilgisayar Dilleri Karşılaştırma Oyunu Scala kodunun Java benzeri bir performans elde etmek için oldukça Java benzeri bir tarzda yazıldığını ve dolayısıyla Java benzeri bellek kullanımına sahip olduğunu unutmayın. Bunu Scala'da yapabilirsiniz: kodunuzu yüksek performanslı Java koduna benzeyecek şekilde yazarsanız, yüksek performanslı Scala kodu olacaktır. (Sen olabilir daha deyimsel Scala tarzında yazmak ve hala iyi bir performans elde edebilmek, ancak özelliklerine bağlıdır.)
Programlama için harcanan zaman başına, Scala kodumun genellikle Java kodumdan daha hızlı olduğunu eklemeliyim çünkü Scala'da performans açısından kritik olmayan sıkıcı parçaları daha az çaba ile yapabilirim ve dikkatimi daha fazla algoritmaları optimize ederek harcayabilirim ve performans açısından kritik parçalar için kod.
Ben yeni bir kullanıcıyım, bu yüzden yukarıdaki Rex Kerr'ın cevabına bir yorum ekleyemiyorum (yeni kullanıcıların "cevap vermesine izin veriyor, ancak" yorum "çok garip bir kural btw).
Rex'in yukarıdaki popüler cevabının "vay canına, Java çok ayrıntılı ve bu kadar zor bir iş" imalarına yanıt vermek için kaydoldum. Elbette daha kısa Scala kodu yazabilirsiniz, ancak verilen Java örneği açıkça şişirilmiştir. Çoğu Java geliştiricisi böyle bir şeyi kodlar:
List<String> bigEnough = new ArrayList<String>();
for(String s : array) {
if(s.length() > 2 && mapping.get(s) != null) {
bigEnough.add(mapping.get(s));
}
}
Ve elbette, Eclipse'in gerçek yazmanın çoğunu sizin için yapmadığını ve kaydedilen her karakterin sizi gerçekten daha iyi bir programcı yaptığını varsayarsak, bunu kodlayabilirsiniz:
List b=new ArrayList();
for(String s:array)
if(s.length()>2 && mapping.get(s) != null) b.add(mapping.get(s));
Şimdi sadece tam değişken isimler ve kıvırcık parantezler yazmak için harcadığım zamanı kurtarmakla kalmadım (derin algoritmik düşünceleri düşünmek için 5 saniye daha harcamamı sağladım), aynı zamanda kodumu gizleme yarışmalarına da girebilir ve potansiyel olarak ekstra para kazanabilirim. Bayram.
Arrays.stream(array).map(mapping::get).filter(x->x!=null).toArray(File[]::new);
Scala'nızı Java gibi yazın ve neredeyse aynı metriklerle neredeyse aynı bayt kodunun yayınlanmasını bekleyebilirsiniz.
Değişmez nesneler ve daha üst düzey işlevlerle daha "deyimsel olarak" yazın ve biraz daha yavaş ve biraz daha büyük olacaktır. Bu genel kuralın tek istisnası, tür parametrelerinin @specialised
ek açıklamayı kullandığı genel nesneleri kullanırken , bu, boks / kutudan kaçınarak Java'nın performansını geride bırakabilecek daha büyük bayt kodu oluşturacaktır.
Ayrıca, paralel olarak çalıştırılabilen kod yazarken daha fazla bellek / daha az hızın kaçınılmaz bir değiş tokuş olduğu gerçeğidir. Deyimsel Scala kodu doğada tipik Java kodundan çok daha bildirgendir ve genellikle .par
tam paralel olmaktan sadece 4 karakter ( ) uzaktadır.
Yani eğer
O zaman Scala kodunun şimdi nispeten% 25 daha yavaş veya 3 kat daha hızlı olduğunu söyleyebilir misiniz?
Doğru cevap, tam olarak "performansı" nasıl tanımladığınıza bağlıdır :)
.par
2.9'da olduğunu belirtmek isteyebilirsiniz .
.par
.
map
yöntemi kullanmayan Scala programlarının sayısı kaybolarak az olacaktır.
Bilgisayar Dil Deneyleri Oyunu:
Hız testi java / scala 1.71 / 2.25
Bellek testi java / scala 66.55 / 80.81
Yani, bu kriterler java'nın% 24 daha hızlı olduğunu ve scala'nın% 21 daha fazla bellek kullandığını söylüyor.
Sonuçta bu büyük bir sorun değil ve çoğu zaman veritabanı ve ağ tarafından tüketildiği gerçek dünya uygulamalarında önemli olmamalıdır.
Alt satır: Scala sizi ve ekibinizi (ve ayrıldığınızda projeyi devralan insanları) daha üretken yaparsa, o zaman bunun için gitmelisiniz.
Diğerleri, Rex Kerr'in yorum yaptığım örnekleri arasında belirgin bir performans farkı var gibi görünse de, bu soruyu sıkı döngülerle cevapladılar.
Bu cevap gerçekten tasarım hatası olarak sıkı döngü optimizasyonu ihtiyacını araştırabilecek insanları hedefliyor.
Scala için nispeten yeniyim (yaklaşık bir yıl kadar) ama şimdiye kadarki hissi , tasarım, uygulama ve yürütmenin birçok yönünü nispeten kolay bir şekilde ertelemenize izin veriyor (yeterli arka plan okuma ve deneme ile :)
Ertelenmiş Tasarım Özellikleri:
Ertelenmiş Uygulama Özellikleri:
Ertelenmiş Yürütme Özellikleri: (üzgünüm, bağlantı yok)
Bu özellikler, bana göre, hızlı ve sıkı uygulamalara giden yolu izlememize yardımcı olan özellikler.
Rex Kerr'ın örnekleri, infazın ertelenmesinde farklıdır. Java örneğinde, bellek tahsisi, Scala örneğinin eşleme aramasını tanımladığı boyut hesaplanıncaya kadar ertelenir. Bana göre tamamen farklı algoritmalar gibi görünüyorlar.
İşte onun daha fazla elma onun elma örneği için elma eşdeğer olduğunu düşünüyorum:
val bigEnough = array.collect({
case k: String if k.length > 2 && mapping.contains(k) => mapping(k)
})
Arada herhangi bir koleksiyon, hiçbir Option
vb örnekleri Bu aynı zamanda o kadar toplama türünü korur bigEnough
'ın türüdür Array[File]
- Array
' ın collect
uygulanması muhtemelen Bay Kerr Java kodu ne çizgisinde bir şey yapacağız.
Yukarıda listelediğim ertelenmiş tasarım özellikleri, Scala'nın koleksiyon API geliştiricilerinin API'yi bozmadan gelecekteki sürümlerde bu hızlı Array'a özgü toplama uygulamasını uygulamasına da izin verecek. Bu, hıza giden yolu işlerken bahsettiğim şey.
Ayrıca:
val bigEnough = array.withFilter(_.length > 2).flatMap(mapping.get)
withFilter
Ben yerine burada kullandım bu yöntem filter
düzeltmeleri ara toplama sorunu ancak Opsiyon örneği sorunu hala var.
Scala'daki basit yürütme hızının bir örneği günlük kaydıdır.
Java'da şöyle bir şey yazabiliriz:
if (logger.isDebugEnabled())
logger.debug("trace");
Scala'da bu sadece:
logger.debug("trace")
çünkü Scala'da hata ayıklamak için kullanılan ileti parametresi, " => String
" değerlendirildiğinde çalıştırılan parametresiz bir işlev olarak düşündüğüm, ancak belgelerin adlarını çapraz olarak çağırdığı " " türüne sahiptir .
EDIT {Scala'daki işlevler nesnedir, bu nedenle burada fazladan bir nesne vardır. Benim işim için, önemsiz bir nesnenin ağırlığı, bir günlük iletisinin gereksiz yere değerlendirilme olasılığını ortadan kaldırmaya değer. }
Bu, kodu daha hızlı yapmaz, ancak daha hızlı olma olasılığını artırır ve diğer insanların kodlarını toplu olarak temizleme deneyimine sahip olma olasılığımız daha düşüktür.
Bana göre, bu Scala içinde tutarlı bir temadır.
Sabit kod, Scala'nın neden daha hızlı olduğunu, ancak biraz ipucu vermediğini yakalayamıyor.
Scala'da kod yeniden kullanımının ve kod kalitesinin tavanının bir kombinasyonu olduğunu hissediyorum.
Java'da harika kod genellikle anlaşılmaz bir karmaşa haline gelmeye zorlanır ve bu nedenle çoğu programcının kullanamayacağı için üretim kalitesi API'larında gerçekten geçerli değildir.
Scala'nın aramızdaki einsteinlerin potansiyel olarak DSL'ler aracılığıyla ifade edilen çok daha yetkin API'leri uygulamasına izin verebileceğine dair umutlarım var. Scala'daki temel API'ler zaten bu yol boyunca.
@higherkinded'in konuyla ilgili sunumu - Bazı Java / Scala karşılaştırmaları yapan Scala Performans Konuları .
Araçlar:
Harika blog yazısı:
Java ve Scala'nın her ikisi de JVM bayt koduna kadar derlenir, bu yüzden fark o kadar büyük değildir. Alabileceğiniz en iyi karşılaştırma, muhtemelen Java ve Scala'nın aynı bellek kullanımına sahip olduğunu söyleyen bilgisayar dili kıyaslama oyunudur . Scala, listelenen bazı ölçütlerde Java'dan biraz daha yavaştır, ancak bunun nedeni programların uygulanmasının farklı olması olabilir.
Gerçekten de, ikisi de o kadar yakın ki endişelenmeye değmez. Scala gibi daha etkileyici bir dil kullanarak elde ettiğiniz verimlilik artışı, minimum (varsa) performans vuruşundan çok daha değerli.
Java and Scala both compile down to JVM bytecode,
birleştirilen gerçek bir ifade göstermek istedim, bunun sadece retorik bir hile olduğunu ve tartışmacı bir sonuç olmadığını. so
diffence isn't that big.
so
Java örneği, tipik uygulama programları için bir deyim değildir. Bu tür optimize edilmiş kod, bir sistem kütüphanesi yönteminde bulunabilir. Ancak daha sonra doğru türde bir dizi kullanır, yani File [] ve bir IndexOutOfBoundsException oluşturmaz. (Sayma ve ekleme için farklı filtre koşulları). Benim sürümüm (her zaman (!) Kıvırcık parantez ile olurdu çünkü Eclipse tek bir tuşa vurmak için 2 saniye kaydederek tanıtılan bir hata aramak için bir saat harcamak istemiyorum):
List<File> bigEnough = new ArrayList<File>();
for(String s : array) {
if(s.length() > 2) {
File file = mapping.get(s);
if (file != null) {
bigEnough.add(file);
}
}
}
Ama size şu anki projemden başka çirkin Java kodu örnekleri getirebilirim. Ortak yapıları ve davranışları çarpanlarına ayırarak ortak kodlama ve kodlama stilini değiştirmeye çalıştım.
Soyut DAO temel sınıfımda ortak önbellek mekanizması için soyut bir iç sınıf var. Her somut model nesne tipi için soyut DAO temel sınıfının bir alt sınıfı vardır, burada iç sınıf, veritabanından yüklendiğinde iş nesnesini oluşturan yöntem için bir uygulama sağlamak üzere alt sınıflandırılır. (Özel bir API aracılığıyla başka bir sisteme eriştiğimiz için ORM aracını kullanamayız.)
Bu alt sınıflandırma ve örnekleme kodu Java'da net değildir ve Scala'da çok okunabilir olacaktır.