क्या इस दावे का समर्थन करता है कि C ++ JVM या CLR के साथ JIT से तेज हो सकती है? [बन्द है]


119

एसई पर एक reoccurring विषय मैंने कई सवालों में देखा है कि चल रहे तर्क यह है कि C ++ जावा के साथ उच्च स्तरीय भाषाओं की तुलना में अधिक तेज और / या अधिक कुशल है। प्रतिवाद यह है कि आधुनिक जेवीएम या सीएलआर जेआईटी के लिए धन्यवाद के रूप में कुशल हो सकता है और इसी तरह कार्यों की बढ़ती संख्या के लिए और सी ++ केवल कभी अधिक कुशल है यदि आप जानते हैं कि आप क्या कर रहे हैं और चीजों को एक निश्चित तरीके से क्यों कर रहे हैं योग्यता में वृद्धि होगी। यह स्पष्ट है और सही समझ में आता है।

मैं एक बुनियादी स्पष्टीकरण जानना चाहता हूं (अगर ऐसी कोई बात है ...) जेवीएम या सीएलआर की तुलना में C ++ में क्यों और कैसे कुछ कार्य तेजी से होते हैं? क्या यह केवल इसलिए है क्योंकि C ++ को मशीन कोड में संकलित किया गया है जबकि JVM या CLR में अभी भी रन टाइम में JIT संकलन का प्रसंस्करण ओवरहेड है?

जब मैं विषय पर शोध करने की कोशिश करता हूं, तो मुझे लगता है कि वही तर्क हैं जो मैंने बिना किसी विस्तृत जानकारी के ऊपर उल्लिखित किए हैं, यह समझने के लिए कि उच्च प्रदर्शन कंप्यूटिंग के लिए C ++ का उपयोग कैसे किया जा सकता है।


प्रदर्शन कार्यक्रम की जटिलता पर भी निर्भर करता है।
14

23
मुझे लगता है कि "C ++ केवल अधिक कुशल है यदि आप जानते हैं कि आप क्या कर रहे हैं और क्यों चीजें एक निश्चित तरीके से कर रही हैं, तो प्रदर्शन में वृद्धि होगी।" यह कहकर कि यह केवल ज्ञान की बात नहीं है, यह डेवलपर समय की बात है। अनुकूलन को अधिकतम करने के लिए यह हमेशा कुशल नहीं है। यही कारण है कि उच्च स्तर की भाषाएं जैसे जावा और पायथन मौजूद हैं (अन्य कारणों के साथ) - एक प्रोग्रामर को अत्यधिक ट्यून किए गए अनुकूलन की कीमत पर किसी दिए गए कार्य को पूरा करने के लिए प्रोग्रामिंग को खर्च करने के लिए समय कम करना पड़ता है।
जोएल कॉर्नेट

4
@ जोएल कॉर्नेट: मैं पूरी तरह से सहमत हूं। मैं निश्चित रूप से जावा में सी ++ की तुलना में अधिक उत्पादक हूं और मैं केवल सी ++ पर विचार करता हूं जब मुझे वास्तव में तेज कोड लिखने की आवश्यकता होती है। दूसरी तरफ मैंने C ++ कोड को बहुत धीमी गति से लिखा हुआ देखा है: अकुशल प्रोग्रामर के हाथों में C ++ कम उपयोगी है।
जियोर्जियो

3
किसी भी संकलित आउटपुट को JIT द्वारा उत्पादित किया जा सकता है, C ++ द्वारा उत्पादित किया जा सकता है, लेकिन C ++ का उत्पादन करने वाला कोड आवश्यक रूप से JIT द्वारा निर्मित नहीं किया जा सकता है। इसलिए C ++ की क्षमताएं और प्रदर्शन विशेषताएँ किसी भी उच्च-स्तरीय भाषा के सुपरसेट हैं। QED
tylerl

1
@Doval तकनीकी रूप से सच है, लेकिन एक नियम के रूप में आप एक हाथ पर कार्यक्रम के प्रदर्शन को प्रभावित करने वाले संभावित रनटाइम कारकों की गणना कर सकते हैं। आमतौर पर दो से अधिक उंगलियों का उपयोग किए बिना। इतना बुरा मामला आप कई बायनेरिज़ को जहाज करते हैं ... सिवाय इसके कि यह पता चले कि आपको ऐसा करने की आवश्यकता भी नहीं है क्योंकि संभावित स्पीडअप नगण्य है, यही वजह है कि कोई भी परेशान नहीं करता है।
टायलरल

जवाबों:


200

यह मेमोरी के बारे में है (जेआईटी नहीं)। जेआईटी 'सी पर लाभ' ज्यादातर आभासी या गैर-आभासी कॉल को इनलाइनिंग के माध्यम से अनुकूलित करने के लिए सीमित है, कुछ ऐसा जो सीपीयू बीटीबी पहले से ही कड़ी मेहनत कर रहा है।

आधुनिक मशीनों में, रैम तक पहुंच वास्तव में धीमी है (सीपीयू कुछ भी करने की तुलना में), जिसका अर्थ है कि एप्लिकेशन जो कि संभव के रूप में कैश का उपयोग करते हैं (जो आसान है जब कम मेमोरी का उपयोग किया जाता है) उन लोगों की तुलना में सौ गुना अधिक तेज हो सकता है। नहीं है। और ऐसे कई तरीके हैं जिनमें जावा C ++ की तुलना में अधिक मेमोरी का उपयोग करता है और उन अनुप्रयोगों को लिखना कठिन बनाता है जो कैश का पूरा फायदा उठाते हैं:

  • प्रत्येक ऑब्जेक्ट के लिए कम से कम 8 बाइट्स का एक मेमोरी ओवरहेड है, और कई स्थानों (अर्थात् मानक संग्रह) में प्राथमिकताओं के बजाय ऑब्जेक्ट्स का उपयोग आवश्यक या पसंद किया जाता है।
  • स्ट्रिंग्स में दो ऑब्जेक्ट होते हैं और 38 बाइट्स का ओवरहेड होता है
  • UTF-16 का उपयोग आंतरिक रूप से किया जाता है, जिसका अर्थ है कि प्रत्येक ASCII वर्ण को एक के बजाय दो बाइट्स की आवश्यकता होती है (Oracle JVM ने हाल ही में शुद्ध ASCII स्ट्रिंग्स के लिए इससे बचने के लिए एक अनुकूलन पेश किया)।
  • कुल संदर्भ प्रकार (यानी संरचनाएं) नहीं है, और बदले में, कुल संदर्भ प्रकारों की कोई सारणी नहीं है। एक जावा ऑब्जेक्ट, या जावा ऑब्जेक्ट्स की सरणी में सी-स्ट्रक्चर्स और सरणियों की तुलना में बहुत खराब एल 1 / एल 2 कैश इलाका है।
  • जावा जेनरिक टाइप-इरेज़र का उपयोग करते हैं, जिसमें टाइप-इंस्टेंटिएशन की तुलना में खराब कैश लोकलिटी है।
  • ऑब्जेक्ट आवंटन अपारदर्शी है और प्रत्येक ऑब्जेक्ट के लिए अलग-अलग किया जाना है, इसलिए किसी एप्लिकेशन के लिए जानबूझकर कैश-फ्रेंडली तरीके से अपना डेटा रखना असंभव है और फिर भी इसे संरचित डेटा के रूप में माना जाता है।

कुछ अन्य मेमोरी- लेकिन कैश-संबंधी कारक नहीं:

  • स्टैक आवंटन नहीं है, इसलिए आपके साथ काम करने वाले सभी गैर-आदिम डेटा को ढेर पर होना चाहिए और कचरा संग्रह के माध्यम से जाना होगा (कुछ हालिया जेआईटी कुछ मामलों में पर्दे के पीछे स्टैक आवंटन करते हैं)।
  • क्योंकि कुल संदर्भ प्रकार नहीं हैं, कुल संदर्भ प्रकारों का कोई स्टैक पासिंग नहीं है। (सदिश तर्कों के कुशल पारगमन के बारे में सोचें)
  • कचरा संग्रह L1 / L2 कैश सामग्री को नुकसान पहुंचा सकता है, और जीसी स्टॉप-द-वर्ल्ड पॉजेस इंटरएक्टिविटी को नुकसान पहुंचाता है।
  • डेटा प्रकारों के बीच परिवर्तित करने के लिए हमेशा प्रतिलिपि की आवश्यकता होती है; आप एक सॉकेट से मिले बाइट्स के एक गुच्छा के लिए एक संकेतक नहीं ले सकते हैं और उन्हें एक फ्लोट के रूप में व्याख्या कर सकते हैं।

इनमें से कुछ चीजें ट्रेडऑफ़ हैं (मैनुअल मेमोरी मैनेजमेंट नहीं करना अधिकांश लोगों के लिए बहुत अधिक प्रदर्शन देने के लायक है ), कुछ संभवतः जावा को सरल रखने की कोशिश करने का परिणाम हैं, और कुछ डिज़ाइन गलतियाँ हैं (हालांकि संभवतः केवल दृष्टिहीनता में , अर्थात् जब जावा बनाया गया था, तो UTF-16 एक निश्चित लंबाई एन्कोडिंग था, जो इसे बहुत अधिक समझने का निर्णय लेता है)।

यह ध्यान देने योग्य है कि इनमें से कई ट्रेडऑफ जावा / जेवीएम के लिए बहुत भिन्न हैं, क्योंकि वे C # / CIL के लिए हैं। .NET CIL में रेफ़रेंस-टाइप स्ट्रक्चर, स्टैक एलोकेशन / पासिंग, स्ट्रक्चर्स के पैक्ड एरेज़ और टाइप-इंस्टेंटिएट जेनरिक हैं।


37
+1 - कुल मिलाकर, यह एक अच्छा जवाब है। हालांकि, मुझे यकीन नहीं है कि "कोई स्टैक आवंटन नहीं है" बुलेट बिंदु पूरी तरह से सटीक है। जावा JITs अक्सर स्टैक आवंटन के लिए अनुमति देने के लिए विश्लेषण से बचते हैं जहां संभव हो - शायद आपको क्या कहना चाहिए कि जावा भाषा प्रोग्रामर को यह तय करने की अनुमति नहीं देती है कि कोई ऑब्जेक्ट स्टैक-आवंटित बनाम ढेर-आवंटित कब किया गया है। इसके अतिरिक्त, अगर एक जेनरेशनल कचरा संग्रहकर्ता (जो सभी आधुनिक जेवीएम उपयोग करते हैं) उपयोग में है, तो "हीप आवंटन" का मतलब पूरी तरह से अलग चीज (पूरी तरह से अलग प्रदर्शन विशेषताओं के साथ) से है जो कि C ++ वातावरण में होता है।
डेनियल प्राइडेन

5
मुझे लगता है कि दो अन्य चीजें हैं लेकिन मैं ज्यादातर सामान के साथ बहुत उच्च स्तर पर काम करता हूं इसलिए यह बताएं कि क्या मैं गलत हूं। आप वास्तव में स्मृति में क्या हो रहा है और मशीन कोड वास्तव में कैसे काम करता है, इस पर कुछ सामान्य जागरूकता विकसित किए बिना आप C ++ नहीं लिख सकते हैं, जबकि स्क्रिप्टिंग या वर्चुअल मशीन भाषाएं जो आपके ध्यान से दूर सभी चीजें सार करती हैं। आपके पास बहुत अधिक ठीक-ठाक नियंत्रण है कि चीजें कैसे काम करती हैं जबकि एक वीएम या व्याख्या की गई भाषा में आप इस बात पर भरोसा कर रहे हैं कि मुख्य पुस्तकालय लेखकों ने एक विशिष्ट विशिष्ट परिदृश्य के लिए क्या अनुकूलित किया हो सकता है।
एरिक रेपेने

18
+1। एक और चीज़ जो मैं जोड़ूंगा (लेकिन मैं उसके लिए एक नया उत्तर प्रस्तुत करने के लिए तैयार नहीं हूं): जावा में सरणी अनुक्रमण हमेशा सीमा जाँच शामिल है। C और C ++ के साथ, यह मामला नहीं है।
रिवालॉक

7
यह ध्यान देने योग्य है कि जावा का हीप आवंटन सी ++ (आंतरिक पूलिंग और चीजों के कारण) के साथ एक भोले संस्करण की तुलना में काफी तेज है, लेकिन सी ++ में मेमोरी आवंटन बेहतर हो सकता है यदि आप जानते हैं कि आप क्या कर रहे हैं।
ब्रेंडन लॉन्ग

10
@BrendanLong, सच है .. लेकिन केवल अगर स्मृति साफ है - एक बार एक ऐप थोड़ी देर के लिए चल रहा है, तो जीसी की आवश्यकता के कारण मेमोरी आवंटन धीमा हो जाएगा, जो चीजों को नाटकीय रूप से धीमा कर देता है क्योंकि इसमें मेमोरी को फ़्री करना है, फ़ाइनलीज़र चलाना और फिर कॉम्पैक्ट। इसका एक ऐसा व्यापार जो बेंचमार्क को लाभान्वित करता है लेकिन (IMHO) समग्र रूप से ऐप्स को धीमा कर देता है।
gbjbaanb

67

क्या यह केवल इसलिए है क्योंकि C ++ को असेंबली / मशीन कोड में संकलित किया गया है जबकि Java / C # में रनटाइम के दौरान JIT संकलन का प्रोसेसिंग ओवरहेड है?

आंशिक रूप से, लेकिन सामान्य तौर पर, एक बिल्कुल शानदार अत्याधुनिक जेआईटी कंपाइलर मानते हुए, उचित C ++ कोड अभी भी दो मुख्य कारणों के लिए जावा कोड से बेहतर प्रदर्शन करता है:

1) C ++ टेम्प्लेट कोड लिखने के लिए बेहतर सुविधाएं प्रदान करता है जो सामान्य और कुशल दोनों हैं । टेम्प्लेट C ++ प्रोग्रामर को एक बहुत ही उपयोगी एब्सट्रैक्शन प्रदान करते हैं जिसमें ZERO रनटाइम ओवरहेड होता है। (टेम्प्लेट मूल रूप से कंपाइल-टाइम डक-टाइपिंग होते हैं।) इसके विपरीत, जावा जेनेरिक के साथ आपको जो सबसे अच्छा मिलता है, वह मूल रूप से आभासी कार्य है। वर्चुअल फ़ंक्शंस में हमेशा एक रनटाइम ओवरहेड होता है, और आम तौर पर इनबिल्ट नहीं किया जा सकता है।

सामान्य तौर पर, जावा, सी # और यहां तक ​​कि सी सहित अधिकांश भाषाएं, आपको दक्षता और सामान्यता / अमूर्तता के बीच चयन करती हैं। C ++ टेम्प्लेट आपको दोनों देते हैं (लंबे संकलन समय की लागत पर)

2) यह तथ्य कि C ++ मानक में संकलित C ++ प्रोग्राम के बाइनरी लेआउट के बारे में कहने के लिए बहुत कुछ नहीं है, C ++ कंपाइलर जावा कंपाइलर की तुलना में बहुत अधिक लेवे देता है, जिससे बेहतर अनुकूलन (कभी-कभी डिबगिंग में अधिक कठिनाई की कीमत पर) की अनुमति मिलती है। ) वास्तव में, जावा भाषा विनिर्देश की बहुत प्रकृति कुछ क्षेत्रों में एक प्रदर्शन जुर्माना लागू करती है। उदाहरण के लिए, आपके पास जावा में ऑब्जेक्ट का एक सन्निहित सरणी नहीं हो सकता है। आपके पास केवल ऑब्जेक्ट पॉइंटर्स का एक सन्निहित सरणी हो सकता है(संदर्भ), जिसका अर्थ है कि जावा में एक सरणी पर पुनरावृति हमेशा अप्रत्यक्ष की लागत को बढ़ाती है। C ++ का मान शब्दार्थ हालांकि, सन्निहित सरणियों को सक्षम करता है। एक और अंतर तथ्य यह है कि सी ++ वस्तुओं को स्टैक पर आवंटित करने की अनुमति देता है, जबकि जावा का अर्थ यह नहीं है कि व्यवहार में, चूंकि ज्यादातर सी ++ प्रोग्राम स्टैक पर ऑब्जेक्ट आवंटित करने के लिए करते हैं, इसलिए आवंटन की लागत अक्सर शून्य के करीब होती है।

एक क्षेत्र जहां C ++ जावा से पिछड़ सकता है, वह ऐसी स्थिति है जहां ढेर पर कई छोटी वस्तुओं को आवंटित करने की आवश्यकता होती है। इस स्थिति में, जावा का कचरा संग्रहण प्रणाली शायद मानक newऔर deleteसी ++ की तुलना में बेहतर प्रदर्शन का परिणाम देगा क्योंकि जावा जीसी बल्क डीलक्लोलेशन को सक्षम बनाता है। लेकिन फिर से, एक C ++ प्रोग्रामर इसके लिए मेमोरी पूल या स्लैब एलोकेटर का उपयोग करके क्षतिपूर्ति कर सकता है, जबकि जावा प्रोग्रामर के पास मेमोरी-आवंटन पैटर्न के साथ सामना करने पर कोई पुनरावृत्ति नहीं होती है जो जावा रनटाइम के लिए अनुकूलित नहीं है।

इसके अलावा, इस विषय के बारे में अधिक जानकारी के लिए यह उत्कृष्ट उत्तर देखें ।


6
अच्छा जवाब है, लेकिन एक छोटी सी बात: "सी ++ टेम्पलेट आपको दोनों (लंबे समय तक संकलन की लागत पर) देते हैं" "मैं बड़े कार्यक्रम के आकार की कीमत पर भी जोड़ूंगा। हमेशा एक समस्या नहीं हो सकती है, लेकिन अगर मोबाइल उपकरणों के लिए विकसित हो रहा है, तो यह निश्चित रूप से हो सकता है।
सिंह

9
@luiscubal: नहीं, इस संबंध में, C # जेनरिक बहुत जावा-जैसे हैं (इसमें समान "जेनेरिक" कोड पथ को कोई फर्क नहीं पड़ता है कि किस प्रकार के माध्यम से पारित किया जाता है।) C ++ टेम्प्लेट की चाल यह है कि कोड एक बार के लिए इंस्टेंट है। हर प्रकार पर लागू होता है। तो std::vector<int>एक गतिशील सरणी है जो सिर्फ किलों के लिए डिज़ाइन की गई है, और संकलक इसके अनुसार अनुकूलन करने में सक्षम है। AC # List<int>अभी भी सिर्फ एक है List
jalf

12
@jalf C # List<int>का उपयोग करता है int[], न Object[]कि जावा जैसा। देखें stackoverflow.com/questions/116988/…
luiscubal

5
@ ग्लिस्कुबल: आपकी शब्दावली अस्पष्ट है। JIT उस कार्य को नहीं करता है जिसे मैं "संकलन-समय" मानता हूँ। आप सही हैं, निश्चित रूप से, पर्याप्त रूप से चतुर और आक्रामक जेआईटी संकलक को देखते हुए, यह प्रभावी रूप से कोई सीमा नहीं है कि यह क्या कर सकता है। लेकिन C ++ को इस व्यवहार की आवश्यकता है। इसके अलावा, सी ++ टेम्पलेट प्रोग्रामर को स्पष्ट विशेषज्ञता निर्दिष्ट करने की अनुमति देते हैं, जहां अतिरिक्त स्पष्ट अनुकूलन को लागू किया जाता है। C # के पास इसके लिए कोई समकक्ष नहीं है। उदाहरण के लिए, C ++ में, मैं एक परिभाषित कर सकता हूं vector<N>कि, के विशिष्ट मामले के लिए vector<4>, मेरे हाथ-कोडित SIMD कार्यान्वयन का उपयोग किया जाना चाहिए
jalf

5
@Leo: 15 साल पहले टेम्प्लेट के जरिए कोड ब्लोट एक समस्या थी। भारी टेंपलाइज़ेशन और इनलाइनिंग के साथ, प्लस एबिलिटी कंपाइलर्स को उठाया गया है (जैसे समान उदाहरणों को मोड़ना), आजकल बहुत सारे कोड टेम्पलेट के माध्यम से छोटे हो जाते हैं।
sbi

46

अन्य उत्तर (अब तक के 6) का उल्लेख करना भूल गए हैं, लेकिन मैं इसका उत्तर देने के लिए बहुत महत्वपूर्ण मानता हूं, सी ++ का एक बहुत ही मूल डिजाइन दर्शन है, जिसे स्ट्रॉन्स्ट्रुप द्वारा दिन 1 से तैयार किया गया था और नियोजित किया गया था:

आप जो उपयोग नहीं करते हैं उसके लिए आप भुगतान नहीं करते हैं।

कुछ अन्य महत्वपूर्ण अंतर्निहित डिज़ाइन सिद्धांत हैं जो बहुत सी आकार देते हैं (जैसे कि आपको एक विशिष्ट प्रतिमान में मजबूर नहीं किया जाना चाहिए), लेकिन आप उन चीज़ों के लिए भुगतान नहीं करते हैं जो आप उपयोग नहीं करते हैं सबसे महत्वपूर्ण लोगों में से एक है।


अपनी पुस्तक द डिजाइन एंड एवोल्यूशन ऑफ सी ++ (आमतौर पर [डी एंड ई] के रूप में संदर्भित) में, स्ट्रॉस्ट्रुप का वर्णन है कि उन्हें किस चीज की आवश्यकता थी, जिससे उन्हें पहली जगह में सी ++ के साथ आना पड़ा। मेरे स्वयं के शब्दों में: अपनी पीएचडी थीसिस (नेटवर्क सिमुलेशन, आईआईआरसी के साथ कुछ करने के लिए) के लिए, उन्होंने SIMULA में एक प्रणाली लागू की, जो उन्हें बहुत पसंद आई, क्योंकि भाषा उन्हें कोड में सीधे अपने विचार व्यक्त करने की अनुमति देने में बहुत अच्छी थी। हालांकि, परिणामी कार्यक्रम बहुत धीमी गति से चला, और एक डिग्री प्राप्त करने के लिए, उन्होंने BCPL में बात को फिर से लिखा, सी। के एक पूर्ववर्ती ने BCPL में कोड लिखकर उन्हें दर्द के रूप में वर्णित किया, लेकिन परिणामी कार्यक्रम तेजी से वितरित करने के लिए पर्याप्त था परिणाम, जिसने उन्हें अपनी पीएचडी खत्म करने की अनुमति दी।

उसके बाद, वह एक ऐसी भाषा चाहता था जो वास्तविक दुनिया की समस्याओं को सीधे कोड में अनुवाद करने की अनुमति दे, लेकिन साथ ही कोड को बहुत कुशल होने की अनुमति देता है।
इसके अनुसरण में, उन्होंने बनाया कि बाद में C ++ क्या होगा।


तो ऊपर उद्धृत लक्ष्य केवल कई मूलभूत अंतर्निहित डिज़ाइन सिद्धांत में से एक नहीं है, यह C ++ के लिए raison d'etre के बहुत करीब है । और यह भाषा में हर जगह बस के बारे में पाया जा सकता है: कार्य केवल virtualतब होते हैं जब आप उन्हें चाहते हैं (क्योंकि आभासी कार्यों को कॉल करना एक मामूली ओवरहेड के साथ आता है) जब आप स्पष्ट रूप से अनुरोध करते हैं तो POD केवल स्वचालित रूप से आरंभिक होते हैं, अपवाद केवल तब आपके प्रदर्शन पर खर्च होते हैं जब आप वास्तव में उन्हें फेंक दें (जबकि स्टैकफ्रेम के सेटअप / सफाई को बहुत सस्ता होने की अनुमति देने के लिए यह एक स्पष्ट डिजाइन लक्ष्य था), कोई जीसी नहीं चल रहा है जब भी ऐसा लगता है, आदि।

C ++ ने स्पष्ट रूप से आपको कुछ उपयुक्तता न देने के लिए चुना है ("क्या मुझे इस विधि को यहां आभासी बनाना है?") प्रदर्शन के बदले में ("नहीं, मैं नहीं, और अब संकलक inlineइसे कर सकते हैं और बिल्ली को बाहर कर सकते हैं।" पूरी बात! "), और, आश्चर्य की बात नहीं है, यह वास्तव में उन भाषाओं की तुलना में प्रदर्शन लाभ के रूप में हुआ है जो अधिक सुविधाजनक हैं।


4
आप जो उपयोग नहीं करते हैं उसके लिए आप भुगतान नहीं करते हैं। => और फिर उन्होंने RTTI :(
Matthieu M.

11
@ मैथ्यू: जबकि मैं आपकी भावना को समझता हूं, मैं मदद नहीं कर सकता, लेकिन ध्यान दें कि यहां तक ​​कि प्रदर्शन के संबंध में भी ध्यान दिया गया है। RTTI निर्दिष्ट किया गया है ताकि वर्चुअल टेबल का उपयोग करके इसे लागू किया जा सके, और यदि आप इसका उपयोग नहीं करते हैं तो बहुत कम ओवरहेड जोड़ता है। यदि आप बहुरूपता का उपयोग नहीं करते हैं, तो कोई लागत नहीं है। क्या मैं कुछ भूल रहा हूँ?
sbi

9
@ मैथ्यू: बेशक, इसका कारण है। लेकिन क्या यह कारण तर्कसंगत है? मैं जो देख सकता हूं, "आरटीटीआई की लागत", यदि उपयोग नहीं किया जाता है, तो प्रत्येक पॉलीमॉर्फ़िक क्लास की वर्चुअल टेबल में एक अतिरिक्त पॉइंटर है, जो आरटीटीआई ऑब्जेक्ट को इंगित करता है कि वह कहीं आवंटित है। जब तक आप मेरे टोस्टर में चिप को प्रोग्राम नहीं करना चाहते, यह कभी प्रासंगिक कैसे हो सकता है?
sbi

4
@Aaronaught: मैं नुकसान में हूं कि इसका क्या जवाब दूं। क्या आपने वास्तव में मेरे उत्तर को केवल इसलिए खारिज कर दिया क्योंकि यह अंतर्निहित दर्शन को इंगित करता है जिसने स्ट्रॉस्ट्रुप एट अल को एक तरह से सुविधाओं को जोड़ा जो प्रदर्शन के लिए अनुमति देता है, बजाय इन तरीकों और सुविधाओं को व्यक्तिगत रूप से सूचीबद्ध करने के?
sbi

9
@Aaronaught: आपको मेरी सहानुभूति है।
sbi

29

क्या आप उस विषय के बारे में Google शोध पत्र जानते हैं?

निष्कर्ष से:

हम पाते हैं कि प्रदर्शन के संबंध में, C ++ बड़े अंतर से जीतता है। हालांकि, इसे सबसे व्यापक ट्यूनिंग प्रयासों की भी आवश्यकता थी, जिनमें से कई परिष्कार के स्तर पर किए गए थे जो औसत प्रोग्रामर के लिए उपलब्ध नहीं होंगे।

यह कम से कम आंशिक रूप से स्पष्टीकरण है, "क्योंकि वास्तविक दुनिया सी ++ संकलक आनुभविक उपायों द्वारा जावा संकलक की तुलना में तेजी से कोड का उत्पादन करता है"।


4
मेमोरी और कैश उपयोग के अंतर के अलावा, सबसे महत्वपूर्ण में से एक अनुकूलन प्रदर्शन की मात्रा है। तुलना करें कि कितने अनुकूलन GCC / LLVM (और शायद विजुअल C ++ / ICC) जावा हॉटस्पॉट कंपाइलर के सापेक्ष करते हैं: बहुत अधिक, विशेषकर लूप के बारे में, निरर्थक शाखाओं को समाप्त करने और आवंटन को पंजीकृत करने के लिए। जेआईटी कंपाइलर्स के पास आमतौर पर इन आक्रामक अनुकूलन के लिए समय नहीं होता है, यहां तक ​​कि सोचा कि वे उपलब्ध रन-टाइम जानकारी का उपयोग करके उन्हें बेहतर तरीके से लागू कर सकते हैं।
ग्रेटियन लुप

2
@GratianLup: मुझे आश्चर्य है कि अगर (अभी भी) LTO के साथ सही है।
Deduplicator

2
@GratianLup: C ++ के लिए प्रोफाइल-गाइडेड ऑप्टिमाइज़ेशन को न भूलें ...
Deduplicator

23

यह आपके प्रश्नों का डुप्लिकेट नहीं है, लेकिन स्वीकृत उत्तर आपके अधिकांश प्रश्नों का उत्तर देता है: जावा की आधुनिक समीक्षा

सारांश में:

मौलिक रूप से, जावा का शब्दार्थ यह बताता है कि यह C ++ की तुलना में धीमी भाषा है।

इसलिए, इस बात पर निर्भर करता है कि आप किस दूसरी भाषा में C ++ की तुलना करते हैं, आपको एक ही उत्तर मिल सकता है या नहीं।

C ++ में आपके पास:

  • स्मार्ट इनलाइनिंग करने की क्षमता,
  • सामान्य कोड जेनरेशन जिनके पास मजबूत स्थानीयता (टेम्प्लेट) हैं
  • जितना संभव हो उतना छोटा और कॉम्पैक्ट डेटा
  • अप्रत्यक्ष से बचने के अवसर
  • पूर्वानुमेय स्मृति व्यवहार
  • उच्च स्तर के अमूर्त (टेम्प्लेट) के उपयोग के कारण ही कंपाइलर अनुकूलन संभव है

ये भाषा की परिभाषा की विशेषताएं या साइड-इफेक्ट्स हैं जो इसे किसी भी भाषा की तुलना में स्मृति और गति पर सैद्धांतिक रूप से अधिक कुशल बनाते हैं:

  • अप्रत्यक्ष रूप से बड़े पैमाने पर उपयोग करें ("सब कुछ एक प्रबंधित संदर्भ / सूचक है" भाषाएँ): अप्रत्यक्ष का अर्थ है कि सीपीयू को आवश्यक डेटा प्राप्त करने के लिए मेमोरी में कूदना पड़ता है, जिससे सीपीयू कैश विफलताओं में वृद्धि होती है, जिसका अर्थ है कि प्रसंस्करण धीमा हो जाता है - सी का उपयोग अप्रत्यक्ष रूप से भी करता है भले ही यह C ++ के रूप में छोटा डेटा हो;
  • बड़े आकार के ऑब्जेक्ट उत्पन्न करते हैं जो सदस्यों को अप्रत्यक्ष रूप से एक्सेस किए जाते हैं: यह डिफ़ॉल्ट रूप से संदर्भ होने का एक परिणाम है, सदस्य पॉइंटर्स होते हैं इसलिए जब आपको कोई सदस्य मिलता है तो आपको मूल ऑब्जेक्ट के कोर के करीब डेटा नहीं मिल सकता है, फिर से कैश मिस को ट्रिगर करना।
  • एक गार्बेज कलेक्टर का उपयोग करें: यह सिर्फ प्रदर्शन की असंभवता (डिजाइन द्वारा) को असंभव बनाता है।

संकलक की C + एग्रेसिव इनलाइनिंग बहुत सारे अप्रत्यक्ष को कम या खत्म कर देती है। कॉम्पैक्ट डेटा के छोटे सेट को उत्पन्न करने की क्षमता इसे कैश फ्रेंडली बनाती है यदि आप इन डेटा को एक साथ पैक करने के बजाय मेमोरी में नहीं फैलाते हैं (दोनों संभव हैं, C ++ सिर्फ आपको चुनने देता है)। RAII वास्तविक समय या अर्ध-वास्तविक-समय सिमुलेशन के मामले में C ++ मेमोरी व्यवहार को बहुत अधिक समस्याग्रस्त बनाता है, जिसके लिए उच्च गति की आवश्यकता होती है। स्थानीयता की समस्याएं, सामान्य रूप से इसके द्वारा सारांशित किया जा सकता है: कार्यक्रम / डेटा जितना छोटा होगा, निष्पादन उतनी ही तेजी से होगा। C ++ आपके डेटा को यह सुनिश्चित करने के लिए विविध तरीके प्रदान करता है कि आप उसे कहाँ चाहते हैं (पूल में, सरणी, या जो भी हो) और यह कॉम्पैक्ट है।

जाहिर है, ऐसी अन्य भाषाएं हैं जो ऐसा कर सकती हैं, लेकिन वे सिर्फ इसलिए कम लोकप्रिय हैं क्योंकि वे सी ++ के रूप में अधिक अमूर्त उपकरण प्रदान नहीं करती हैं, इसलिए वे बहुत सारे मामलों में कम उपयोगी नहीं हैं।


7

यह मुख्य रूप से मेमोरी के बारे में है (जैसा कि माइकल बोर्गवर्ड ने कहा था) जेआईटी अक्षमता के एक बिट के साथ।

एक बात का उल्लेख नहीं किया गया है - कैश का पूरी तरह से उपयोग करने के लिए, आपको अपने डेटा को आकस्मिक रूप से (यानी सभी को एक साथ) रखना होगा। अब GC सिस्टम के साथ, मेमोरी को GC heap पर आवंटित किया जाता है, जो कि त्वरित है, लेकिन जैसे ही मेमोरी का उपयोग किया जाता है GC नियमित रूप से किक करेगा और उन ब्लॉकों को हटा देगा जो अब उपयोग नहीं किए जाते हैं और फिर शेष को एक साथ कॉम्पैक्ट करते हैं। अब उन प्रयुक्त ब्लॉकों को एक साथ ले जाने की स्पष्ट सुस्ती के अलावा, इसका मतलब है कि आपके द्वारा उपयोग किए जा रहे डेटा एक साथ अटक नहीं सकते हैं। यदि आपके पास 1000 तत्वों की एक सरणी है, जब तक कि आप उन सभी को एक साथ आवंटित नहीं करते हैं (और फिर हटाने और नए बनाने के बजाय उनकी सामग्री को अपडेट किया है - जो कि ढेर के अंत में बनाया जाएगा) ये सभी ढेर में बिखरे हुए हो जाएंगे, इस प्रकार उन सभी को सीपीयू कैश में पढ़ने के लिए कई मेमोरी हिट की आवश्यकता होती है। एसी / सी ++ ऐप सबसे अधिक इन तत्वों के लिए मेमोरी आवंटित करेगा और फिर आप डेटा के साथ ब्लॉक को अपडेट करेंगे। (ठीक है, एक सूची की तरह डेटा संरचनाएं हैं जो जीसी मेमोरी आवंटन की तरह अधिक व्यवहार करती हैं, लेकिन लोग जानते हैं कि ये वैक्टर की तुलना में धीमी हैं)

आप इसे किसी भी StringBuilder वस्तुओं को String के साथ बदलकर ऑपरेशन में देख सकते हैं ... Stringbuilders स्मृति को पूर्व-आबंटित करके और उसे भरने का काम करते हैं, और java / .NET सिस्टम के लिए एक ज्ञात प्रदर्शन चाल है।

यह न भूलें कि जावा / C # में 'पुरानी को हटाएं और नई प्रतियां आवंटित करें' प्रतिमान बहुत अधिक उपयोग किया जाता है, बस इसलिए कि लोगों को बताया जाता है कि मेमोरी आवंटन जीसी के कारण वास्तव में तेज हैं, और इसलिए बिखरे हुए स्मृति मॉडल का उपयोग हर जगह हो जाता है ( स्ट्रिपुलेटर्स को छोड़कर, निश्चित रूप से) इसलिए आपके सभी पुस्तकालय स्मृति की बर्बादी करते हैं और इसका बहुत अधिक उपयोग करते हैं, जिनमें से किसी को भी आकस्मिकता का लाभ नहीं मिलता है। इसके लिए जीसी के आसपास प्रचार को दोष दें - उन्होंने आपको स्मृति मुक्त, योग्य बताया था।

जीसी खुद स्पष्ट रूप से एक और हिट है - जब यह चलता है, तो इसे न केवल ढेर के माध्यम से स्वीप करना पड़ता है, बल्कि इसे सभी अप्रयुक्त ब्लॉकों को भी मुक्त करना पड़ता है, और फिर इसे किसी भी फाइनल को चलाना पड़ता है (हालांकि यह अलग से किया जाता था। अगली बार ऐप रुकने के साथ) (मुझे नहीं पता कि क्या यह अभी भी इतनी बढ़िया हिट है, लेकिन मैंने जो सभी डॉक्स पढ़े हैं वे केवल यह कहते हैं कि यदि आवश्यक हो तो केवल फाइनल का उपयोग करें) और फिर इसे उन ब्लॉकों को स्थिति में स्थानांतरित करना है ताकि ढेर है संकुचित, और ब्लॉक के नए स्थान के संदर्भ को अद्यतन करें। जैसा कि आप देख सकते हैं, इसका बहुत काम है!

C ++ मेमोरी के लिए परफेक्ट हिट्स मेमोरी एलोकेशन के लिए नीचे आता है - जब आपको एक नए ब्लॉक की आवश्यकता होती है, तो आपको अगले फ्री स्पेस की तलाश में हीप चलना होगा, जो कि काफी बड़ा हो, भारी खंडित ढेर के साथ, यह लगभग GC के जितना तेज़ नहीं है 'बस अंत में एक और ब्लॉक आवंटित करें' लेकिन मुझे लगता है कि यह उतना धीमा नहीं है जितना कि जीसी संघनन सभी काम करता है, और कई निश्चित आकार के ब्लॉक ढेर (अन्यथा मेमोरी पूल के रूप में जाना जाता है) का उपयोग करके इसे कम किया जा सकता है।

GAC से अधिक लोडिंग असेंबली की तरह ... सुरक्षा जाँच की आवश्यकता है, जांच पथ ( sxstrace को चालू करें और बस यह देखें कि यह क्या हो रहा है!) और सामान्य अन्य अतिवृद्धि जो java / .net के साथ अधिक लोकप्रिय लगती है। C / C ++ से।


2
आपके द्वारा लिखी गई कई चीजें आधुनिक जनरेशनल कचरा संग्रहकर्ताओं के लिए सही नहीं हैं।
माइकल बॉर्गवर्ड

3
@MichaelBorgwardt जैसे? मैं कहता हूं "जीसी नियमित रूप से चलता है" और "यह ढेर को संकुचित करता है"। मेरे जवाब की बाकी चिंताएं कि एप्लिकेशन डेटा संरचनाएं मेमोरी का उपयोग कैसे करती हैं।
gbjbaanb

6

"क्या यह केवल इसलिए है क्योंकि C ++ को असेंबली / मशीन कोड में संकलित किया गया है जबकि Java / C # में अभी भी रनटाइम पर JIT संकलन का प्रसंस्करण ओवरहेड है?" मूल रूप से, हाँ!

त्वरित नोट हालांकि, जावा में सिर्फ JIT संकलन की तुलना में अधिक ओवरहेड्स हैं। उदाहरण के लिए, यह आपके लिए बहुत अधिक जाँच करता है (जो है कि यह कैसे काम करता है जैसे ArrayIndexOutOfBoundsExceptionsऔर NullPointerExceptions)। कचरा संग्रहकर्ता एक और महत्वपूर्ण ओवरहेड है।

यहाँ एक बहुत विस्तृत तुलना है


2

ध्यान रखें कि निम्नलिखित केवल देशी और जेआईटी संकलन के बीच अंतर की तुलना कर रहा है, और किसी विशेष भाषा या रूपरेखा की बारीकियों को कवर नहीं करता है। इससे परे एक विशेष मंच को चुनने के लिए वैध कारण हो सकते हैं।

जब हम दावा करते हैं कि मूल कोड जल्दी है, तो हम विशिष्ट उपयोग के मामले के बारे में बात कर रहे हैं मूल रूप से संकलित कोड बनाम JIT संकलित कोड के , जहां उपयोगकर्ता द्वारा JIT संकलित आवेदन का विशिष्ट उपयोग तत्काल परिणामों के साथ चलाया जाना है (जैसे, नहीं पहले कंपाइलर पर प्रतीक्षा की जा रही है)। उस स्थिति में, मुझे नहीं लगता कि कोई भी सीधे चेहरे के साथ दावा कर सकता है, कि जेआईटी संकलित कोड देशी कोड को मैच या हरा सकता है।

मान लेते हैं कि हमारे पास कुछ भाषा X में लिखा गया प्रोग्राम है, और हम इसे एक देशी कंपाइलर के साथ, और फिर से JIT कंपाइलर के साथ संकलित कर सकते हैं। प्रत्येक कार्य प्रवाह में एक ही चरण शामिल होता है, जिसे (कोड -> मध्यवर्ती प्रतिनिधित्व -> मशीन कोड -> निष्पादन) के रूप में सामान्यीकृत किया जा सकता है। दो में बड़ा अंतर यह है कि कौन से चरण उपयोगकर्ता द्वारा देखे जाते हैं और जो प्रोग्रामर द्वारा देखे जाते हैं। मूल संकलन के साथ, प्रोग्रामर सभी लेकिन निष्पादन चरण देखता है, लेकिन जेआईटी समाधान के साथ, मशीन कोड के संकलन को निष्पादन के अतिरिक्त, उपयोगकर्ता द्वारा देखा जाता है।

दावा है कि A, B से तेज है , कार्यक्रम को चलाने में लगने वाले समय का उल्लेख करता है, जैसा कि उपयोगकर्ता द्वारा देखा गया है । यदि हम मानते हैं कि कोड के दोनों टुकड़े निष्पादन चरण में पहचान करते हैं, तो हमें यह मान लेना चाहिए कि JIT कार्य प्रवाह उपयोगकर्ता के लिए धीमा है, क्योंकि उसे मशीन कोड के संकलन का समय T भी देखना होगा, जहां T> 0. तो , जेआईटी कार्य प्रवाह की किसी भी संभावना के लिए, मूल कार्य प्रवाह को उपयोगकर्ता के समान करने के लिए, हमें कोड के निष्पादन के समय को कम करना होगा, जैसे कि निष्पादन + मशीन कोड का संकलन, केवल निष्पादन चरण से कम है मूल कार्य प्रवाह के। इसका मतलब है कि हमें जेआईटी संकलन में देशी संकलन की तुलना में बेहतर कोड का अनुकूलन करना चाहिए।

हालांकि, यह संभव नहीं है, क्योंकि निष्पादन में तेजी लाने के लिए आवश्यक अनुकूलन करने के लिए, हमें मशीन कोड चरण के संकलन में अधिक समय बिताना होगा, और इस प्रकार, किसी भी समय हम अनुकूलित कोड के परिणामस्वरूप बचत करते हैं, वास्तव में खो जाता है, जैसा कि हम इसे संकलन में जोड़ते हैं। दूसरे शब्दों में, JIT आधारित समाधान का "सुस्ती" केवल JIT संकलन के लिए जोड़े गए समय के कारण नहीं है, बल्कि उस संकलन द्वारा निर्मित कोड एक देशी समाधान की तुलना में धीमी गति से कार्य करता है।

मैं एक उदाहरण का उपयोग करूंगा: आवंटन आवंटित करें। चूँकि मेमोरी एक्सेस रजिस्टर एक्सेस की तुलना में कुछ हज़ार गुना धीमी है, हम आदर्श रूप से जहाँ भी संभव हो रजिस्टरों का उपयोग करना चाहते हैं और हमारे पास जितनी भी मेमोरी एक्सेस हो सकती है, लेकिन हमारे पास सीमित संख्या में रजिस्टर हैं, और हमें आवश्यकता पड़ने पर मेमोरी में स्टेट को भेजना होगा। एक रजिस्टर। यदि हम एक रजिस्टर आवंटन एल्गोरिथ्म का उपयोग करते हैं जो गणना करने के लिए 200ms लेता है, और परिणामस्वरूप हम निष्पादन के समय के 2ms को बचाते हैं - हम JIT कंपाइलर के लिए समय का सबसे अच्छा उपयोग नहीं कर रहे हैं। चैटिन के एल्गोरिथ्म जैसे समाधान, जो अत्यधिक अनुकूलित कोड का उत्पादन कर सकते हैं अनुपयुक्त हैं।

JIT कंपाइलर की भूमिका, उत्पादन कोड के संकलन समय और गुणवत्ता के बीच के सर्वश्रेष्ठ संतुलन पर प्रहार करना है, हालाँकि, तेज़ संकलन समय पर एक बड़े पूर्वाग्रह के साथ, क्योंकि आप उपयोगकर्ता प्रतीक्षा को छोड़ना नहीं चाहते हैं। जेईटी मामले में निष्पादित किए जा रहे कोड का प्रदर्शन धीमा है, क्योंकि देशी कंपाइलर कोड के अनुकूलन में समय से बाध्य (बहुत) नहीं है, इसलिए सर्वश्रेष्ठ एल्गोरिदम का उपयोग करने के लिए स्वतंत्र है। संभावना है कि एक JIT संकलक के लिए समग्र संकलन + निष्पादन मूल रूप से संकलित कोड के लिए केवल निष्पादन समय को हरा सकता है प्रभावी रूप से 0।

लेकिन हमारे वीएम केवल जेआईटी संकलन तक सीमित नहीं हैं। वे अहेड-ऑफ-टाइम संकलन तकनीक, कैशिंग, हॉट स्वैपिंग और अनुकूली अनुकूलन का उपयोग करते हैं। तो चलिए हमारे दावे को संशोधित करते हैं कि प्रदर्शन वही है जो उपयोगकर्ता देखता है, और इसे कार्यक्रम के निष्पादन के लिए लिए गए समय तक सीमित करें (मान लें कि हमने एओटी संकलित किया है)। हम प्रभावी रूप से निष्पादन कोड को मूल संकलक (या शायद बेहतर?) के बराबर बना सकते हैं। VMs के लिए एक बड़ा दावा यह है कि वे बेहतर गुणवत्ता कोड तब एक देशी संकलक का उत्पादन करने में सक्षम हो सकते हैं, क्योंकि इसमें अधिक जानकारी तक पहुंच है - जो चल रही प्रक्रिया की, जैसे कि एक निश्चित फ़ंक्शन को कितनी बार निष्पादित किया जा सकता है। VM गर्म स्वैपिंग के माध्यम से सबसे आवश्यक कोड के लिए अनुकूली अनुकूलन लागू कर सकता है।

हालांकि इस तर्क के साथ एक समस्या है - यह मानता है कि प्रोफ़ाइल-निर्देशित अनुकूलन और वीएम के लिए कुछ अद्वितीय है, जो सच नहीं है। हम इसे मूल संकलन पर भी लागू कर सकते हैं - प्रोफाइलिंग सक्षम के साथ हमारे आवेदन को संकलित करके, सूचना दर्ज करना, और फिर उस प्रोफ़ाइल के साथ आवेदन को फिर से जमा करना। यह शायद यह भी इंगित करने योग्य है कि कोड हॉट स्वैपिंग कुछ ऐसा नहीं है जो केवल एक जेआईटी कंपाइलर ही कर सकता है, हम इसे देशी कोड के लिए भी कर सकते हैं - हालांकि ऐसा करने के लिए जेआईटी आधारित समाधान अधिक आसानी से उपलब्ध हैं, और डेवलपर पर बहुत आसान है। तो बड़ा सवाल यह है कि क्या कोई वीएम हमें कुछ ऐसी जानकारी दे सकता है जो देशी संकलन नहीं कर सकता, जो हमारे कोड के प्रदर्शन को बढ़ावा दे सकता है?

मैं इसे खुद नहीं देख सकता। हम एक विशिष्ट वीएम की अधिकांश तकनीकों को मूल कोड में भी लागू कर सकते हैं - हालांकि प्रक्रिया अधिक शामिल है। इसी तरह, हम एक मूल संकलक के किसी भी अनुकूलन को एक वीएम पर वापस लागू कर सकते हैं जो एओटी संकलन या अनुकूली अनुकूलन का उपयोग करता है। वास्तविकता यह है कि मूल रूप से रन कोड के बीच अंतर है, और एक वीएम में रन उतना बड़ा नहीं है जितना कि हमें विश्वास करने के लिए बनाया गया है। वे अंततः उसी परिणाम का नेतृत्व करते हैं, लेकिन वे वहां पहुंचने के लिए एक अलग दृष्टिकोण लेते हैं। VM अनुकूलित कोड का उत्पादन करने के लिए एक पुनरावृत्त दृष्टिकोण का उपयोग करता है, जहां मूल संकलक इसे शुरू से उम्मीद करता है (और पुनरावृत्त दृष्टिकोण के साथ इसमें सुधार किया जा सकता है)।

एक C ++ प्रोग्रामर यह तर्क दे सकता है कि उसे गेट-गो से ऑप्टिमाइज़ेशन की आवश्यकता है, और वीएम का इंतजार नहीं करना चाहिए ताकि उन्हें पता चले कि उन्हें कैसे करना है। यह शायद हमारी वर्तमान तकनीक के साथ एक वैध बिंदु है, हालांकि, हमारे वीएम में वर्तमान स्तर का अनुकूलन मूल संकलक क्या पेशकश कर सकता है - से हीन है, लेकिन ऐसा हमेशा नहीं हो सकता है यदि हमारे वीएम में एओटी समाधान में सुधार हो, आदि।


0

यह लेख c ++ बनाम c # की गति की तुलना करने की कोशिश कर रहे ब्लॉग पोस्ट के एक समूह का सारांश है और जिन मुद्दों को आपको उच्च प्रदर्शन कोड प्राप्त करने के लिए दोनों भाषाओं में दूर करना होगा। सारांश यह है कि '' आपकी लाइब्रेरी कुछ भी नहीं की तुलना में अधिक है, लेकिन अगर आप c ++ में हैं तो आप इसे दूर कर सकते हैं। ' या 'आधुनिक भाषाओं में बेहतर पुस्तकालय हैं और इस प्रकार आपके दार्शनिक तिरस्कार के आधार पर कम प्रयास के साथ तेजी से परिणाम प्राप्त होते हैं।


0

मुझे लगता है कि यहाँ असली सवाल यह नहीं है कि "कौन सा तेज़ है?" लेकिन "जो उच्च प्रदर्शन के लिए सबसे अच्छी क्षमता है?"। उन शर्तों पर देखा गया, C ++ स्पष्ट रूप से जीतता है - यह मूल कोड के लिए संकलित है, कोई JITting नहीं है, यह अमूर्त स्तर का निचला स्तर है, आदि।

वह पूरी कहानी से बहुत दूर है।

क्योंकि C ++ संकलित है, किसी भी कंपाइलर ऑप्टिमाइज़ेशन को कंपाइल समय पर किया जाना चाहिए, और कंपाइलर ऑप्टिमाइज़ेशन जो एक मशीन के लिए उपयुक्त हैं, दूसरे के लिए पूरी तरह से गलत हो सकता है। यह भी मामला है कि कोई भी वैश्विक संकलक अनुकूलन कुछ एल्गोरिदम या दूसरों पर कोड पैटर्न का पक्ष ले सकता है।

दूसरी ओर, एक JITted प्रोग्राम JIT समय पर ऑप्टिमाइज़ हो जाएगा, इसलिए यह कुछ ट्रिक्स खींच सकता है जो कि एक precompiled प्रोग्राम नहीं कर सकता है और मशीन के लिए बहुत विशिष्ट अनुकूलन कर सकता है जो वास्तव में चल रहा है और कोड जो वास्तव में चल रहा है। एक बार जब आप JIT के प्रारंभिक ओवरहेड को पार कर लेते हैं तो उसमें कुछ मामलों में तेजी आने की संभावना होती है।

दोनों मामलों में एल्गोरिथ्म के एक समझदार कार्यान्वयन और प्रोग्रामर के अन्य उदाहरणों के बेवकूफ नहीं होने की संभावना अधिक महत्वपूर्ण कारक होंगे, हालांकि - उदाहरण के लिए, सी ++ में पूरी तरह से ब्रेन-डेड स्ट्रिंग कोड लिखना पूरी तरह से संभव है जो कि यहां तक ​​कि दीवार से घिरा होगा। एक व्याख्यात्मक भाषा।


3
"संकलक अनुकूलन जो एक मशीन के लिए उपयुक्त हैं, दूसरे के लिए पूरी तरह से गलत हो सकता है" ठीक है, यह वास्तव में भाषा पर दोष नहीं है। ट्रूली परफॉर्मेंस-क्रिटिकल कोड को प्रत्येक मशीन के लिए अलग से संकलित किया जा सकता है जो उस पर चलेगी, जो कि एक नो-ब्रेनर है यदि आप स्रोत से स्थानीय रूप से संकलन करते हैं ( -march=native)। - "यह अमूर्तता का एक निचला स्तर है" वास्तव में सच नहीं है। C ++ जावा के रूप में उच्च-स्तरीय अमूर्त के रूप में उपयोग करता है (या, वास्तव में, उच्चतर: कार्यात्मक प्रोग्रामिंग; टेम्पलेट मेट्रोग्रामग्रामिंग?), यह सिर्फ जावा की तुलना में कम "साफ़" सार लागू करता है।
वामावर्तबाउट

"ट्रूली परफॉर्मेंस-क्रिटिकल कोड को प्रत्येक मशीन के लिए अलग-अलग संकलित किया जा सकता है, जो उस पर चलेगा, जो कि नो-ब्रेनर है यदि आप स्रोत से स्थानीय रूप से संकलित करते हैं" - यह अंतर्निहित धारणा के कारण विफल हो जाता है कि एंड-यूज़र भी एक प्रोग्रामर है।
मैक्सिमस मिनिमस

जरूरी नहीं कि अंतिम उपयोगकर्ता, केवल प्रोग्राम को स्थापित करने के लिए जिम्मेदार व्यक्ति हो। डेस्कटॉप और मोबाइल उपकरणों पर, कि आम तौर पर है अंत उपयोगकर्ता, लेकिन ये केवल अनुप्रयोगों देखते हैं निश्चित रूप से सबसे अधिक प्रदर्शन के लिए महत्वपूर्ण लोगों नहीं नहीं कर रहे हैं। और आपको वास्तव में स्रोत से प्रोग्राम बनाने के लिए एक प्रोग्रामर होने की आवश्यकता नहीं है , अगर यह ठीक से सभी अच्छे स्वतंत्र / ओपन प्रोजेक्ट प्रोजेक्ट जैसी स्क्रिप्ट का निर्माण करता है।
लेफ्टरनैबाउट

1
सिद्धांत रूप में हां, एक जेआईटी एक स्थिर संकलक की तुलना में अधिक चालें खींच सकता है, व्यवहार में (.NET के लिए कम से कम, मैं जावा को भी नहीं जानता), यह वास्तव में इसमें से कोई भी नहीं करता है। मैंने हाल ही में .NET JIT कोड के असंतुष्टीकरण का एक गुच्छा किया है, और लूप से बाहर कोड को फहराने, डेड कोड एलिमिनेशन, इत्यादि जैसे सभी प्रकार के अनुकूलन हैं, जो .NET JIT बस नहीं करता है। काश, यह होता, लेकिन हे, माइक्रोसॉफ्ट के अंदर विंडोज़ टीम सालों से .NET को मारने की कोशिश कर रही है, इसलिए मैं अपनी सांस नहीं रोक रहा हूं
ओरियन एडवर्ड्स

-1

JIT संकलन वास्तव में प्रदर्शन पर नकारात्मक प्रभाव डालता है। यदि आप एक "सही" संकलक और एक "परिपूर्ण" JIT संकलक डिज़ाइन करते हैं, तो पहला विकल्प हमेशा प्रदर्शन में जीत जाएगा।

जावा और सी # दोनों को मध्यवर्ती भाषाओं में व्याख्या की जाती है, और फिर रनटाइम पर मूल कोड के लिए संकलित किया जाता है, जो प्रदर्शन को कम करता है।

लेकिन अब अंतर सी # के लिए स्पष्ट नहीं है: माइक्रोसॉफ्ट सीएलआर विभिन्न सीपीयू के लिए अलग-अलग मूल कोड का उत्पादन करता है, इस प्रकार कोड को मशीन को चलाने के लिए अधिक कुशल बनाता है, जो हमेशा सी ++ कंपाइलर द्वारा नहीं किया जाता है।

PS C # बहुत प्रभावशाली तरीके से लिखा गया है और इसमें कई अमूर्त परतें नहीं हैं। यह जावा के लिए सही नहीं है, जो कि कुशल नहीं है। तो, इस मामले में, अपने greate CLR के साथ, C # प्रोग्राम अक्सर C ++ कार्यक्रमों की तुलना में बेहतर प्रदर्शन दिखाते हैं। .Net और CLR के बारे में अधिक जानने के लिए जेफरी रिक्टर के "CLR थ्रू C #" पर एक नज़र डालें ।


8
यदि वास्तव में JIT के प्रदर्शन पर नकारात्मक प्रभाव पड़ता है, तो निश्चित रूप से इसका उपयोग नहीं किया जाएगा?
Zavior

2
@Zavior - मैं आपके प्रश्न के अच्छे उत्तर के बारे में नहीं सोच सकता, लेकिन मैं यह नहीं देखता कि JIT अतिरिक्त प्रदर्शन को कैसे नहीं जोड़ सकता - JIT रन टाइम में पूरी होने वाली एक अतिरिक्त प्रक्रिया है जिसके लिए संसाधनों की आवश्यकता होती है ' कार्यक्रम के निष्पादन पर खर्च किया जा रहा है, जबकि एक पूरी तरह से संकलित भाषा 'जाने के लिए तैयार' है।
अनाम

3
JIT के प्रदर्शन पर सकारात्मक प्रभाव पड़ता है, नकारात्मक नहीं, यदि आप इसे संदर्भ में रखते हैं - इसे चलाने से पहले मशीन कोड में बाइट कोड संकलित कर रहा है। परिणामों को भी कैश किया जा सकता है, इसकी व्याख्या की गई समकक्ष बाइट-कोड की तुलना में तेज़ी से चलने की अनुमति मिलती है।
केसी कुबाल

3
JIT (या बल्कि, बाइटकोड दृष्टिकोण) का उपयोग प्रदर्शन के लिए नहीं, बल्कि सुविधा के लिए किया जाता है। प्रत्येक प्लेटफ़ॉर्म (या एक सामान्य सबसेट, जो उनमें से हर एक के लिए उप-इष्टतम है) के लिए प्री-बिल्डिंग बायनेरिज़ के बजाय, आप केवल आधे रास्ते को संकलित करते हैं और जेआईटी कंपाइलर को बाकी काम करने देते हैं। 'एक बार लिखो, कहीं भी तैनात करो' इसीलिए ऐसा किया गया है। सुविधा सिर्फ एक बाईटकोड दुभाषिया के साथ किया था जा सकता है लेकिन JIT कच्चे दुभाषिया की तुलना में तेजी से यह पड़ता है (हालांकि जरूरी काफी तेजी से नहीं एक पूर्व संकलित समाधान को हरा करने के लिए; JIT संकलन करता है समय लेने के लिए है, और परिणाम हमेशा ऊपर नहीं है इसके लिए)।
tdammers 15

4
@ टैडमर्स, वास्तव में एक प्रदर्शन घटक भी है। Java.sun.com/products/hotspot/whitepaper.html देखें । ऑप्टिमाइज़ेशन में शाखा भविष्यवाणी और कैश हिट, डायनामिक इनलाइनिंग, डी-वर्चुअलाइज़ेशन, सीमा जाँच की अक्षमता और लूप अनरोलिंग को बेहतर बनाने के लिए गतिशील समायोजन जैसी चीज़ें शामिल हो सकती हैं। दावा है कि कई मामलों में ये जेआईटी की लागत से अधिक हो सकते हैं।
चार्ल्स ई। ग्रांट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.