İlk olarak, çoğu JVM bir derleyici içerir, bu nedenle "yorumlanan bayt kodu" aslında oldukça nadirdir (en azından kıyaslama kodunda - gerçek hayatta olduğu kadar nadir değildir, kodunuz genellikle çok sık tekrarlanan birkaç önemsiz döngüden daha fazladır) ).
İkincisi, söz konusu ölçütlerin çok sayıda önyargısı var gibi görünüyor (kasıtlı veya beceriksizce, gerçekten söyleyemem). Örneğin, yıllar önce, gönderdiğiniz bağlantılardan birine bağlı olan kaynak kodların bazılarına baktım. Bunun gibi bir kodu vardı:
init0 = (int*)calloc(max_x,sizeof(int));
init1 = (int*)calloc(max_x,sizeof(int));
init2 = (int*)calloc(max_x,sizeof(int));
for (x=0; x<max_x; x++) {
init2[x] = 0;
init1[x] = 0;
init0[x] = 0;
}
Yana calloc
kullanmakta, sıfırlanmış oluyor bellek sağlar for
bunu sıfır döngü tekrar açıkçası işe yaramaz. Bunu (eğer hafıza çalışıyorsa) yine de diğer verilerle doldurmak (ve sıfırlanmamasına bağımlı olmak yok) takip etti, böylece tüm sıfırlama yine de tamamen gereksizdi. Basit Yukarıdaki kodu değiştirilmesi malloc
(bellek hizmet veriyorsa, oldukça geniş bir farkla) (herhangi bir akıllı kişi ile başlatmak için kullanılan olurdu gibi) yeterli Java sürüm yenmek için C ++ sürüm hızı geliştirilmiş.
methcall
Son bağlantıda blog girişinde kullanılan ölçütü düşünün (başka bir örnek için) . İsim (ve nasıl işler daha görünebilir) rağmen, bu C ++ sürüm olduğu değil gerçekten hiç yöntem çağrısı yükü hakkında çok ölçme. Kodun kritik olduğu ortaya çıkan kısmı Toggle sınıfında:
class Toggle {
public:
Toggle(bool start_state) : state(start_state) { }
virtual ~Toggle() { }
bool value() {
return(state);
}
virtual Toggle& activate() {
state = !state;
return(*this);
}
bool state;
};
Kritik kısım olduğu ortaya çıkıyor state = !state;
. Biz devlet olarak kodlamak için kodunu değiştirmek ne olur düşünün int
yerine ait bool
:
class Toggle {
enum names{ bfalse = -1, btrue = 1};
const static names values[2];
int state;
public:
Toggle(bool start_state) : state(values[start_state])
{ }
virtual ~Toggle() { }
bool value() { return state==btrue; }
virtual Toggle& activate() {
state = -state;
return(*this);
}
};
Bu küçük değişiklik genel hızı yaklaşık 5: 1 oranında artırır . Kriter olsa da amaçlanan gerçekte, o ölçme şeyin en yöntem çağrısı süresini ölçmek için arasında dönüştürme zamanı gelmişti int
ve bool
. Orijinalin gösterdiği verimsizliğin talihsiz olduğuna kesinlikle katılıyorum - ancak gerçek kodda ne kadar nadir ortaya çıktığı göz önüne alındığında ve ne zaman ortaya çıkarsa düzeltilebilme kolaylığı göz önüne alındığında, zor bir zaman geçirdiğimi düşünüyorum. bunun anlamı olarak.
Herhangi birisinin söz konusu kriterleri yeniden çalıştırmaya karar vermesi durumunda, üreten Java sürümünde neredeyse eşit derecede önemsiz bir değişiklik yapıldığını da eklemeliyim. Son JVM hala yaptıklarını onaylamak için) Java sürümünde de oldukça önemli bir gelişme. Java sürümünde buna benzeyen bir NthToggle :: activate () var:
public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
this.state = !this.state;
this.counter = 0;
}
return(this);
}
Bunu this.state
doğrudan işlemek yerine temel işlevi çağırmak için değiştirmek , önemli ölçüde hız artışı sağlar (ancak değiştirilmiş C ++ sürümüne yetişmek için yeterli olmamakla birlikte).
Dolayısıyla, sonuçta yorumlanan bayt kodları ve şimdiye kadar gördüğüm en kötü kıyaslamaların bazıları hakkında yanlış bir varsayım var. İkisi de anlamlı bir sonuç vermiyor.
Benim kendi deneyimim, eşit derecede deneyimli programcıların optimizasyona eşit derecede dikkat etmesiyle, C ++ 'nın Java'yı sık sık yenmeyeceği - ama (en azından bu ikisi arasında), dil programcılar ve tasarım kadar nadiren fark yaratacaktır. Alıntılanan kriterler bize yazarlarının (in) yetkinliği / (dis) dürüstlüğü hakkında, kıyaslamada kullandıkları diller hakkında yaptıklarından daha fazlasını anlatır.
[Düzenleme: Yukarıda bir yerde belirtildiği gibi, ancak muhtemelen olması gerektiği gibi doğrudan belirtilmediği gibi, alıntı yaptığım sonuçlar, şu anda mevcut olan C ++ ve Java uygulamalarını kullanarak bu ~ 5 yıl önce test ettiğimde elde ettiğim sonuçlar. . Testleri mevcut uygulamalarla tekrar başlatmadım. Bununla birlikte, bir bakışta, kodun düzeltilmediğini, bu nedenle değiştirilebilecek tek şey derleyicinin koddaki sorunları örtme becerisi olacağını gösterir.]
Biz Java örneklerini görmezden gelirsek, ancak olduğu yorumlanır kodu (zor ve biraz alışılmadık olsa da) derlenmiş kod daha hızlı çalıştırmak için aslında mümkün.
Bunun olmasının genel yolu, yorumlanmakta olan kodun makine kodundan çok daha küçük olması veya kod önbelleğinden daha büyük veri önbelleği olan bir CPU'da çalışmasıdır.
Böyle bir durumda, küçük bir tercüman (örneğin, bir Forth uygulamasının iç tercümanı) tamamen kod önbelleğine sığabilir ve yorumladığı program tamamen veri önbelleğine sığabilir. Önbellek, genellikle en az 10 ve genellikle çok daha fazla bir faktörle ana bellekten daha hızlıdır (100 faktörü artık çok nadir değildir).
Öyleyse, önbellek ana bellekten N faktörü ile daha hızlıysa ve her bayt kodunu uygulamak için N makine kodu talimatından daha az sürerse, bayt kodunun kazanması gerekir (basitleştiriyorum, ancak genel fikrimin hala devam etmesi gerektiğini düşünüyorum). belirgin olun).