सबसे पहले, अधिकांश जेवीएम में एक संकलक शामिल होता है, इसलिए "व्याख्या की गई बायोटेक" वास्तव में बहुत दुर्लभ है (कम से कम बेंचमार्क कोड में - यह वास्तविक जीवन में बहुत दुर्लभ नहीं है, जहां आपका कोड आमतौर पर कुछ तुच्छ छोरों से अधिक होता है जो अक्सर दोहराए जाते हैं )।
दूसरा, शामिल किए गए बेंचमार्क की एक उचित संख्या काफी पक्षपाती प्रतीत होती है (चाहे इरादे या अक्षमता से, मैं वास्तव में नहीं कह सकता)। उदाहरण के लिए, वर्षों पहले मैंने आपके द्वारा पोस्ट किए गए लिंक में से कुछ स्रोत कोड को देखा था। यह इस तरह कोड था:
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;
}
चूंकि calloc
स्मृति पहले से ही for
शून्य है , लूप का उपयोग करके इसे फिर से शून्य करने के लिए स्पष्ट रूप से बेकार है। मेमोरी को अन्य डेटा के साथ (और शून्य होने पर कोई निर्भरता नहीं) भरने के बाद इसका अनुसरण किया गया था, इसलिए सभी शून्यिंग वैसे भी पूरी तरह से अनावश्यक थीं। ऊपर दिए गए कोड को सरल के साथ बदलना malloc
(जैसे किसी भी समझदार व्यक्ति के साथ शुरू करने के लिए इस्तेमाल किया होगा) ने जावा संस्करण को हरा देने के लिए C ++ संस्करण की गति में काफी सुधार किया (यदि स्मृति कार्य करती है तो काफी व्यापक अंतर से)।
methcall
अपने अंतिम लिंक में ब्लॉग प्रविष्टि में प्रयुक्त बेंचमार्क पर विचार करें (एक अन्य उदाहरण के लिए) । नाम (और चीजें कैसे भी दिख सकती हैं) के बावजूद, इस का सी ++ संस्करण वास्तव में विधि कॉल ओवरहेड के बारे में बिल्कुल भी माप नहीं कर रहा है। कोड का वह भाग जो महत्वपूर्ण हो जाता है, टॉगल वर्ग में है:
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;
};
महत्वपूर्ण हिस्सा निकला state = !state;
। विचार करें कि जब हम राज्य को एक के int
बजाय कोड को बदलने के लिए कोड बदलते हैं तो क्या होता है 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);
}
};
यह मामूली बदलाव समग्र गति में 5: 1 के अंतर से सुधार करता है । भले ही बेंचमार्क का उद्देश्य विधि कॉल समय को मापने का था, लेकिन वास्तव में यह जो माप रहा था वह था कि यह बीच में परिवर्तित होने का समय था int
और bool
। मैं निश्चित रूप से सहमत हूं कि मूल द्वारा दिखाई गई अक्षमता दुर्भाग्यपूर्ण है - लेकिन यह देखते हुए कि वास्तविक कोड में यह शायद ही कभी उत्पन्न होता है, और जिस आसानी से इसे तय किया जा सकता है, अगर यह उत्पन्न होता है, तो मुझे एक मुश्किल समय लगता है। इसका उतना ही अर्थ है।
यदि कोई भी इसमें शामिल बेंचमार्क को फिर से चलाने का फैसला करता है, तो मुझे यह भी जोड़ना चाहिए कि जावा संस्करण में लगभग समान रूप से तुच्छ संशोधन है जो उत्पादन करता है (या कम से कम एक बार उत्पादित - मैं एक के साथ परीक्षण फिर से नहीं चलाता हूं हाल के जेवीएम की पुष्टि करने के लिए वे अभी भी जावा संस्करण में काफी सुधार कर रहे हैं। जावा संस्करण में एक NthToggle :: सक्रिय () है जो इस तरह दिखता है:
public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
this.state = !this.state;
this.counter = 0;
}
return(this);
}
this.state
सीधे मैनिपुलेट करने के बजाय बेस फ़ंक्शन को कॉल करने के लिए इसे बदलने से काफी गति में सुधार होता है (हालांकि संशोधित सी 1 संस्करण के साथ रखने के लिए पर्याप्त नहीं है)।
इसलिए, हम जिस चीज के साथ अंत करते हैं, वह बाइट कोड्स के बारे में व्याख्या करने का एक गलत अनुमान है। न ही सार्थक परिणाम दे रहा है।
मेरा खुद का अनुभव है कि समान रूप से अनुभवी प्रोग्रामर अनुकूलन के लिए समान ध्यान देते हैं, सी ++ जावा को अधिक बार नहीं - बल्कि कम से कम (इन दोनों के बीच) को हरा देगा, भाषा शायद ही कभी प्रोग्रामर्स और डिज़ाइन के रूप में उतना अंतर करेगी। जिन बेंचमार्क का हवाला दिया जा रहा है, वे हमारे लेखकों की ईमानदारी (in) क्षमता / (डिस) के बारे में अधिक बताते हैं, क्योंकि वे उन भाषाओं के बारे में करते हैं, जो वे बेंचमार्क को बताते हैं।
[संपादित करें: जैसा कि ऊपर एक जगह में निहित है, लेकिन जैसा कि मुझे शायद कभी नहीं होना चाहिए, जैसा कि मैंने कभी नहीं किया था, जो परिणाम मुझे बताए जा रहे हैं, वे हैं जो मुझे मिले ~ 5 साल पहले, मैंने C ++ और जावा कार्यान्वयन का उपयोग किया था जो उस समय चालू थे। । मैंने वर्तमान कार्यान्वयन के साथ परीक्षणों को फिर से नहीं चलाया है। हालाँकि, एक नज़र यह इंगित करता है कि कोड को ठीक नहीं किया गया है, इसलिए यह सब बदल जाता है जो कोड में समस्याओं को कवर करने के लिए संकलक की क्षमता होगी।]
अगर हम जावा उदाहरण उपेक्षा, तथापि, यह है वास्तव में संभव व्याख्या कोड संकलित कोड की तुलना में तेजी से चलाने के लिए के लिए (हालांकि मुश्किल और कुछ हद तक असामान्य)।
ऐसा होने का सामान्य तरीका यह है कि जिस कोड की व्याख्या की जा रही है वह मशीन कोड की तुलना में बहुत अधिक कॉम्पैक्ट है, या यह सीपीयू पर चल रहा है जिसमें कोड कैश से बड़ा डेटा कैश है।
ऐसे मामले में, एक छोटा दुभाषिया (जैसे, एक फोर्थ कार्यान्वयन का आंतरिक दुभाषिया) पूरी तरह से कोड कैश में फिट हो सकता है, और यह जिस कार्यक्रम की व्याख्या कर रहा है वह पूरी तरह से डेटा कैश में फिट बैठता है। कैश आमतौर पर कम से कम 10 के कारक द्वारा मुख्य मेमोरी से तेज होता है, और अक्सर बहुत अधिक होता है (100 का कारक विशेष रूप से दुर्लभ नहीं है)।
इसलिए, यदि कैश N के एक कारक द्वारा मुख्य मेमोरी से तेज है, और यह प्रत्येक बाइट कोड को लागू करने के लिए एन मशीन कोड निर्देशों से कम लेता है, तो बाइट कोड को जीतना चाहिए (मैं सरल कर रहा हूं, लेकिन मुझे लगता है कि सामान्य विचार अभी भी होना चाहिए स्पष्ट होना)।