क्या आधुनिक OO भाषाएँ C ++ की सरणी स्टोर प्रदर्शन के साथ प्रतिस्पर्धा कर सकती हैं?


40

मैंने अभी देखा कि हर आधुनिक OO प्रोग्रामिंग भाषा जिसे मैं कम से कम कुछ हद तक परिचित हूँ (जो मूल रूप से सिर्फ जावा, C # और D है) कोवरिएन्ट एरेज़ की अनुमति देता है। यह है, एक स्ट्रिंग सरणी एक वस्तु सरणी है:

Object[] arr = new String[2];   // Java, C# and D allow this

सहसंयोजक सरणियाँ स्थैतिक प्रकार प्रणाली में एक छेद हैं। वे टाइप त्रुटियों को संभव बनाते हैं, जिन्हें संकलन-समय पर पता नहीं लगाया जा सकता है, इसलिए किसी सरणी में प्रत्येक रनटाइम पर जांच की जानी चाहिए:

arr[0] = "hello";        // ok
arr[1] = new Object();   // ArrayStoreException

अगर मैं बहुत सारी सरणी स्टोर करता हूं तो यह एक भयानक प्रदर्शन हिट जैसा लगता है।

C ++ में सहसंयोजक सरणियाँ नहीं हैं, इसलिए ऐसे रनटाइम चेक करने की कोई आवश्यकता नहीं है, जिसका अर्थ है कि कोई निष्पादन जुर्माना नहीं है।

क्या रनटाइम चेक की संख्या कम करने के लिए कोई विश्लेषण आवश्यक है? उदाहरण के लिए, अगर मैं कहूं:

arr[1] = arr[0];

कोई यह तर्क दे सकता है कि स्टोर संभवतः विफल नहीं हो सकता। मुझे यकीन है कि मेरे द्वारा सोचा नहीं गए बहुत सारे अन्य संभावित अनुकूलन हैं।

क्या आधुनिक संकलक वास्तव में इस प्रकार के अनुकूलन करते हैं, या क्या मुझे इस तथ्य के साथ रहना होगा कि, उदाहरण के लिए, एक क्विकसॉर्ट हमेशा ओ (एन लॉग एन) अनावश्यक रनटाइम चेक करता है?

क्या आधुनिक OO भाषाएँ सह-वैरिएंट सरणियों का समर्थन करके बनाए गए ओवरहेड से बच सकती हैं?


7
मैं उलझन में हूं कि आप यह क्यों सुझाव दे रहे हैं कि C ++ अन्य भाषाओं की तुलना में तेज है एक सुविधा C ++ भी समर्थन नहीं करती है।

17
@eco: C ++ सरणी एक्सेस के साथ तेज़ है क्योंकि यह सह-वैरिएंट सरणियों का समर्थन नहीं करता है। फ्रेड जानना चाहता है कि क्या "आधुनिक OO भाषाओं" के लिए सह-वैरिएंट सरणियों के ओवरहेड को C ++ गति के करीब लाना संभव है।
मूविंग डक

13
"कोड जो संकलित करता है, लेकिन रन-टाइम पर अपवाद फेंकता है, बुरी खबर है"

4
@ जेसे और लाखों लोग गतिशील भाषाओं में विश्वसनीय, उच्च मापनीय कोड लिखते हैं। Imo: यदि आप अपने कोड के लिए परीक्षण के मामले नहीं लिखते हैं तो मुझे परवाह नहीं है कि संकलक त्रुटियां हैं या नहीं, मैं किसी भी तरह इस पर भरोसा नहीं करने जा रहा हूं।
वू

7
@ जेसे और कब आप अपवादों की उम्मीद करेंगे लेकिन रनटाइम के दौरान? समस्या कोड नहीं है जो रनटाइम पर अपवाद फेंकता है - ऐसे बहुत सारे मामले हैं जो अच्छी समझ में आता है - समस्या कोड है जो गलत होने की गारंटी है जिसे संकलक द्वारा पकड़ा नहीं जाता है, बल्कि इसके परिणामस्वरूप अपवाद होता है क्रम।
जोनाथन एम डेविस

जवाबों:


33

डी में सहसंयोजक सरणियाँ नहीं हैं। इसने उन्हें सबसे हालिया रिलीज़ ( dmd 2.057 ) से पहले अनुमति दी , लेकिन उस बग को ठीक कर दिया गया है।

डी में एक सरणी एक सूचक और एक लंबाई के साथ प्रभावी रूप से सिर्फ एक संरचना है:

struct A(T)
{
    T* ptr;
    size_t length;
}

किसी सरणी को अनुक्रमित करते समय सामान्य रूप से सीमा की जाँच की जाती है, लेकिन जब आप इसे संकलित करते हैं तो इसे हटा दिया जाता है -release। इसलिए, रिलीज़ मोड में, C / C ++ और D में उन सरणियों के बीच कोई वास्तविक प्रदर्शन अंतर नहीं है।


प्रतीत होता है - d-programming-language.org/arrays.html कहते हैं, "एक स्थिर सरणी T[dim]परोक्ष निम्न में से एक के लिए परिवर्तित किया जा सकता है: ... U[]... एक गतिशील सरणी T[]परोक्ष निम्न में से एक के लिए परिवर्तित किया जा सकता है: U[]। .. जहां Uका एक आधार वर्ग है T। ”
बेन वोइगट

2
@BenVoigt तब ऑनलाइन डॉक्स को अपडेट करना होगा। वे हमेशा दुर्भाग्य से 100% अप-टू-डेट नहीं होते हैं। रूपांतरण के साथ काम करेंगे const U[], के बाद से तो आप सरणी के तत्वों के गलत प्रकार असाइन नहीं कर सकते, लेकिन T[]निश्चित रूप से करता है नहीं करने के लिए कनवर्ट U[]जब तक U[]परिवर्तनशील है। इससे पहले की तरह कोवरिएंट एरेस की अनुमति देना एक गंभीर डिजाइन दोष था जिसे अब ठीक कर दिया गया है।
जोनाथन एम डेविस

@JonathanMDavis: सहसंयोजक सरणियाँ icky हैं, लेकिन कोड के विशेष परिदृश्य के लिए अच्छी तरह से काम करते हैं जो केवल एक सरणी तत्वों को लिखेंगे जो उसी सरणी से पढ़े गए हैं । डी कैसे एक को एक विधि लिखने की अनुमति देगा जो मनमाने प्रकार के सरणियों को सॉर्ट कर सके?
सुपरकाट

@ सुपरकारक यदि आप एक फ़ंक्शन लिखना चाहते हैं जो मनमाने प्रकार का है, तो उसे टेम्पलेटेट करें। उदा। dlang.org/phobos/std_algorithm.html#sort
जोनाथन एम डेविस

21

हां, एक महत्वपूर्ण अनुकूलन यह है:

sealed class Foo
{
}

C # में, यह वर्ग किसी भी प्रकार के लिए एक सुपरस्क्रिप्ट नहीं हो सकता है, इसलिए आप किसी प्रकार की सरणी के लिए चेक से बच सकते हैं Foo

और दूसरे प्रश्न के लिए, F # में सह-वैरिएंट सरणियों की अनुमति नहीं है (लेकिन मुझे लगता है कि चेक CLR में रहेगा जब तक कि यह रनटाइम में अनुकूलन में अनावश्यक नहीं पाया जाता)

let a = [| "st" |]
let b : System.Object[] = a // Fails

https://stackoverflow.com/questions/7339013/array-covariance-in-f

कुछ हद तक संबंधित समस्या सरणी बाउंड-चेकिंग है। यह एक दिलचस्प (लेकिन पुराना) सीएलआर में किए गए अनुकूलन के बारे में पढ़ा जा सकता है (सहवास का भी 1 स्थान बताया गया है): http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds जाँच करें-उन्मूलन-इन-द-clr.aspx


2
स्काला इस निर्माण को भी रोकता है: val a = Array("st"); val b: Array[Any] = aअवैध है। (हालांकि, स्काला में सरणियां हैं ... विशेष जादू ... अंतर्निहित जेवीएम का उपयोग करने के कारण।)
पीएसटी

13

जावा उत्तर:

मुझे लगता है कि आपने वास्तव में कोड को बेंचमार्क नहीं किया है, क्या आपके पास है? सामान्य तौर पर जावा में सभी गतिशील जातियों में से 90% स्वतंत्र हैं क्योंकि जेआईटी उन्हें खत्म कर सकती है (एस्कॉर्ट इसके लिए एक अच्छा उदाहरण होना चाहिए) और बाकी एक ld/cmp/brक्रम हैं जो बिल्कुल अनुमानित है (यदि नहीं, तो ठीक है कि नरक आपके कोड को क्यों फेंक रहा है उन सभी गतिशील कलाकारों अपवाद?)।

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

कुछ ओवरहेड? ज़रूर, लेकिन मुझे शक है कि आप कभी भी इसे नोटिस करेंगे ..


मेरे उत्तर का समर्थन करने में मदद करने के लिए, कृपया इस डॉ। क्लिफ क्लिक ब्लॉगपोस्ट पर जावा बनाम सी प्रदर्शन पर चर्चा करें


10

D सहसंयोजक सरणियों की अनुमति नहीं देता है।

void main()
{
    class Foo {}
    Object[] a = new Foo[10];
}  

/* Error: cannot implicitly convert expression (new Foo[](10LU)) of type Foo[]
to Object[] */

जैसा कि आप कहते हैं, यह अनुमति देने के लिए टाइप सिस्टम में एक छेद होगा।

आपको गलती के लिए माफ़ किया जा सकता है, क्योंकि यह बग केवल अंतिम डीएमडी में तय किया गया था, जिसे 13 दिसंबर को जारी किया गया था।

D में ऐरे एक्सेस C या C ++ की तरह ही तेज़ है।


D-programming-language.org/arrays.html के अनुसार "एक स्थैतिक सरणी T [मंद] को निम्नलिखित में से किसी एक में रूपांतरित किया जा सकता है: ... U [] ... एक गतिशील सरणी T [] को कथित रूप से परिवर्तित किया जा सकता है। निम्नलिखित में से एक: U [] ... जहां U, T का एक आधार वर्ग है। "
बेन वोइग्ट

1
@BenVoigt: पुरानी तारीखों में से।
बीसीएस

1
@BenVoigt: मैंने प्रलेखन अद्यतन करने के लिए एक पुल अनुरोध बनाया है। उम्मीद है कि जल्द ही इसका समाधान हो जाएगा। इस पर ध्यान दिलाने के लिए धन्यवाद।
पीटर अलेक्जेंडर

5

परीक्षण से मैंने एक सस्ते लैपटॉप पर किया है, उपयोग करने के बीच का अंतर int[]और Integer[]लगभग 1.0 ns है। प्रकार के लिए अतिरिक्त जांच के कारण अंतर होने की संभावना है।

आम तौर पर वस्तुओं का उपयोग केवल उच्च स्तर के तर्क के लिए किया जाता है, जब प्रत्येक एनएस मायने नहीं रखता है। यदि आपको हर एनएस को बचाने की आवश्यकता है, तो मैं वस्तुओं की तरह उच्च स्तर के निर्माणों का उपयोग करने से बचूंगा। अकेले असाइनमेंट किसी भी वास्तविक कार्यक्रम में बहुत छोटे कारक होने की संभावना है। उदाहरण के लिए एक ही मशीन पर एक नया ऑब्जेक्ट बनाना 5 ns है।

यदि आप स्ट्रिंग जैसी जटिल वस्तु का उपयोग कर रहे हैं, तो तुलना करने के लिए कॉल बहुत अधिक महंगी, एस्प होने की संभावना है।


2

आपने अन्य आधुनिक OO भाषाओं के बारे में पूछा? ठीक है, डेल्फी stringएक वस्तु नहीं बल्कि एक आदिम होने से पूरी तरह से इस समस्या से बचा जाता है । तो तार की एक सरणी वास्तव में तार की एक सरणी है और कुछ नहीं, और उन पर कोई भी ऑपरेशन देशी कोड जितना तेज़ हो सकता है, किसी भी प्रकार की ओवरहेड की जाँच नहीं कर सकता है।

हालांकि, स्ट्रिंग सरणियों का उपयोग बहुत बार नहीं किया जाता है; डेल्फी प्रोग्रामर TStringListवर्ग का पक्ष लेते हैं । ओवरहेड की एक न्यूनतम राशि के लिए यह स्ट्रिंग-समूह विधियों का एक सेट प्रदान करता है जो इतने सारे परिस्थितियों में उपयोगी होते हैं कि वर्ग की तुलना स्विस आर्मी नाइफ से की गई है। इसलिए स्ट्रिंग स्ट्रिंग के बजाय स्ट्रिंग सूची ऑब्जेक्ट का उपयोग करना मुहावरेदार है।

सामान्य रूप से अन्य वस्तुओं के लिए, समस्या मौजूद नहीं है क्योंकि डेल्फी में, सी ++ की तरह, यहां वर्णित प्रकार के प्रकार के छेद को रोकने के लिए, सरणियों को सहसंयोजक नहीं हैं।


1

या क्या मुझे इस तथ्य के साथ रहना है कि, उदाहरण के लिए, एक क्विकॉर्ट हमेशा O (n लॉग एन) अनावश्यक रनटाइम चेक करता है?

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

इस व्यवहार का कारण यह है कि बाउंड चेकिंग मेमोरी में कोड के संरेखण को संशोधित करता है, कैश हिट आदि की आवृत्ति को संशोधित करेगा।

तो हाँ, इस तथ्य के साथ जियो कि क्विकॉर्ट हमेशा ओ (एन लॉग एन) सहज चेक करता है और प्रोफाइलिंग के बाद ऑप्टिमाइज़ करता है।


1

स्काला एक ओओ भाषा है जिसमें सहसंयोजक, सरणियों के बजाय, अपरिवर्तनीय है। यह JVM को लक्षित करता है, इसलिए वहां कोई प्रदर्शन नहीं जीता है, लेकिन यह जावा और C # दोनों के लिए एक आम बात से बचा जाता है जो पश्चगामी संगतता के कारणों के लिए उनकी प्रकार-सुरक्षा से समझौता करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.