क्या ऑब्जेक्ट-ओरिएंटेशन वास्तव में एल्गोरिदम के प्रदर्शन को प्रभावित करता है?


14

ऑब्जेक्ट एल्गोरिदम ने मुझे कई एल्गोरिदम को लागू करने में बहुत मदद की है। हालांकि, ऑब्जेक्ट-ओरिएंटेड भाषाएं कभी-कभी आपको "सीधे" दृष्टिकोण में मार्गदर्शन करती हैं और मुझे संदेह है कि क्या यह दृष्टिकोण हमेशा एक अच्छी बात है।

OO कोडिंग एल्गोरिदम में तेजी से और आसानी से मददगार है। लेकिन क्या यह OOP प्रदर्शन के आधार पर सॉफ़्टवेयर के लिए नुकसान का कारण हो सकता है यानी प्रोग्राम कितनी तेज़ी से निष्पादित होता है?

उदाहरण के लिए, डेटा संरचना में ग्राफ़ नोड्स को संग्रहीत करना पहली जगह में "सीधा" लगता है, लेकिन अगर नोड ऑब्जेक्ट में कई विशेषताएं और विधियां हैं, तो क्या यह धीमी एल्गोरिथ्म के लिए नेतृत्व कर सकता है?

दूसरे शब्दों में, कई अलग-अलग वस्तुओं के बीच कई संदर्भ हो सकते हैं, या कई वर्गों से कई तरीकों का उपयोग करने के परिणामस्वरूप "भारी" कार्यान्वयन हो सकता है?


1
काफी अजीब सवाल। मैं समझ सकता हूं कि ओओपी वास्तुकला के स्तर पर कैसे मदद करता है। लेकिन एल्गोरिदम कार्यान्वयन का एक स्तर आम तौर पर अमूर्त पर बनाया गया है जो ओओपी के लिए किसी भी चीज के लिए बहुत ही विदेशी हैं। तो, संभावना है, प्रदर्शन आपके ओओपी एल्गोरिदम कार्यान्वयन के लिए सबसे बड़ी समस्या नहीं है। OOP के साथ प्रदर्शन के लिए, सबसे बड़ी अड़चन सामान्य रूप से आभासी कॉल से संबंधित है।
एसके-लॉजिक

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

यदि आपके ग्राफ़ में नोड्स में एक सौ विशेषताएँ हैं, तो आपको वास्तविक कार्यान्वयन के लिए उपयोग किए जाने वाले प्रतिमान की परवाह किए बिना उन्हें संग्रहीत करने के लिए जगह की आवश्यकता होगी, और मैं नहीं देखता कि सामान्य रूप से किसी एकल प्रतिमान को इस पर बढ़त कैसे मिलती है। @deadalnix: कुछ अनुकूलन को कठिन बनाने के कारण शायद लगातार फैक्टर खराब हो सकते हैं। लेकिन ध्यान दें कि मैं कठिन कहता हूं , असंभव नहीं है - उदाहरण के लिए, PyPy टाइट लूप में ऑब्जेक्ट्स को अनबॉक्स कर सकते हैं और जेवीएम हमेशा के लिए वर्चुअल फ़ंक्शन कॉल को इनलाइन कर रहे हैं।

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

1
+1 एल्गोरिदम के साथ ऑब्जेक्ट ओरिएंटेशन से संबंधित, कुछ ऐसा जो इन दिनों अनदेखी है, सॉफ्टवेयर उद्योग और अकादमी दोनों में ...
umlcat

जवाबों:


17

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

संख्यात्मक पुस्तकालयों को देखें। उनमें से बहुत सारे (न केवल 60 या 70 के दशक में लिखे गए) OOP नहीं हैं। इसका एक कारण है कि - संख्यात्मक एल्गोरिदम modulesइंटरफेस और एनकैप्सुलेशन के साथ OO पदानुक्रम की तुलना में डिकॉउप्ड के सेट के रूप में बेहतर काम करते हैं ।


2
इसका मुख्य कारण यह है कि OO संस्करण को कुशल बनाने के लिए केवल C ++ ने एक्सप्रेशन टेम्प्लेट का उपयोग करने का पता लगाया।
डेडएमजी

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

3
वा-वा-क्या? मुझे लगता है कि मैं क्वांट_देव और एसके-तर्क की तुलना में एक अलग ग्रह से आता हूं। नहीं, एक अलग ब्रह्मांड। भौतिकी और सब कुछ के विभिन्न कानूनों के साथ।
माइक नाकिस

5
@ मायकेनकिस: दृष्टिकोण में अंतर (1) में निहित है कि क्या कम्प्यूटेशनल कोड का एक निश्चित हिस्सा ओओपी से मानव-पठनीयता के संदर्भ में लाभान्वित हो सकता है (जो संख्यात्मक व्यंजनों नहीं हैं); (2) क्या OOP वर्ग का डिज़ाइन इष्टतम डेटा संरचना और एल्गोरिथ्म के साथ संरेखित करता है (मेरा उत्तर देखें); और (3) क्या अप्रत्यक्ष की प्रत्येक परत पर्याप्त "मूल्य" प्रदान करती है (प्रति कार्य कॉल या प्रति परत वैचारिक स्पष्टता के संदर्भ में) ओवरहेड को सही ठहराती है (अप्रत्यक्ष, फ़ंक्शन कॉल, परतों या डेटा प्रतिलिपि के कारण)। (४) अंत में, कंपाइलर / JIT / अनुकूलक का परिष्कार कारक सीमित है।
रवांग

2
@ मायकेनकिस, आपका क्या मतलब है? क्या आपको लगता है कि एसटीएल एक ओओपी पुस्तकालय है? जेनेरिक प्रोग्रामिंग वैसे भी OOP के साथ अच्छी तरह से नहीं चलती है। और यह उल्लेख करने की आवश्यकता नहीं है कि ओओपी एक बहुत ही संकीर्ण ढांचा है, जो केवल कुछ ही व्यावहारिक कार्यों के लिए उपयुक्त है, और कुछ के लिए विदेशी।
तर्क

9

प्रदर्शन क्या निर्धारित करता है?

बुनियादी बातें: डेटा संरचनाएं, एल्गोरिदम, कंप्यूटर वास्तुकला, हार्डवेयर। प्लस ओवरहेड।

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

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

कैविएट: व्यापार सॉफ्टवेयर में प्रदर्शन मायने रखता है?

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

इष्टतम प्रदर्शन का क्या मतलब है?

सामान्य तौर पर, सॉफ़्टवेयर प्रदर्शन के साथ समस्या यह है कि: यह साबित करने के लिए कि "एक तेज़ संस्करण मौजूद है", उस तेज़ संस्करण को पहले अस्तित्व में आना होगा (अर्थात स्वयं के अलावा कोई प्रमाण नहीं)।

कभी-कभी उस तेज़ संस्करण को पहली बार एक अलग भाषा या प्रतिमान में देखा जाता है। इसे सुधार के लिए एक संकेत के रूप में लिया जाना चाहिए, न कि कुछ अन्य भाषाओं या प्रतिमानों की हीनता का निर्णय।

हम ओओपी क्यों कर रहे हैं यदि यह इष्टतम प्रदर्शन के लिए हमारी खोज में बाधा डाल सकता है?

OOP "वर्कबिलिटी" में सुधार के बदले में ओवरहेड (अंतरिक्ष और निष्पादन में) का परिचय देता है, और इसलिए कोड का व्यावसायिक मूल्य। यह आगे के विकास और अनुकूलन की लागत को कम करता है। @MikeNakis देखें ।

OOP के कौन से भाग शुरू में उप-इष्टतम डिजाइन को प्रोत्साहित कर सकते हैं?

OOP के कुछ भाग (i) सरलता / सहजता को प्रोत्साहित करते हैं, (ii) मूल सिद्धांतों के बजाय बोलचाल की डिजाइन विधियों का उपयोग, (iii) एक ही उद्देश्य के कई अनुरूप कार्यान्वयन को हतोत्साहित करते हैं।

  • चुम्मा
  • YAGNI
  • सूखी
  • ऑब्जेक्ट डिज़ाइन (जैसे CRC कार्ड के साथ) मूल सिद्धांतों के समान विचार दिए बिना)

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

ओओपी ओवरहेड्स के लिए आम मितली क्या हैं?

जैसा कि पहले कहा गया है, डेटा संरचनाओं का उपयोग करना जो डिजाइन के लिए इष्टतम हैं।

कुछ भाषाएं कोड इनलाइनिंग का समर्थन करती हैं जो कुछ रनटाइम प्रदर्शन को पुनर्प्राप्त कर सकती हैं।

हम प्रदर्शन का त्याग किए बिना OOP को कैसे अपना सकते हैं?

ओओपी और फंडामेंटल दोनों को जानें और लागू करें।

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

क्या ऐसे कोड हैं जो OOP से लाभान्वित नहीं होंगे?

([@Quant_dev], [@ SK-तर्क] और [@MikeNakis] के बीच चर्चा से विस्तारित)

  1. संख्यात्मक व्यंजनों, जो गणित से उत्पन्न होते हैं।
    • गणितीय समीकरण और खुद को रूपांतरित करने वाली वस्तुओं के रूप में समझा जा सकता है।
    • कुशल निष्पादन योग्य कोड उत्पन्न करने के लिए बहुत परिष्कृत कोड परिवर्तन तकनीकों की आवश्यकता होती है। भोले ("श्वेत-बोर्ड") कार्यान्वयन में घृणित प्रदर्शन होगा।
    • हालाँकि, आज के मुख्यधारा के कंपाइलर ऐसा करने में असमर्थ हैं।
    • विशिष्ट सॉफ्टवेयर (MATLAB और Mathematica, आदि) में कुछ उप-समस्याओं के लिए कुशल कोड उत्पन्न करने में सक्षम JIT और प्रतीकात्मक सॉल्वर दोनों हैं। इन विशेष सॉल्वरों को विशेष-उद्देश्य संकलक (मानव-पठनीय कोड और मशीन-निष्पादन योग्य कोड के बीच मध्यस्थ) के रूप में देखा जा सकता है जो स्वयं एक ओओपी डिजाइन से लाभान्वित होंगे।
    • प्रत्येक उप-समस्या के लिए अपने स्वयं के "कंपाइलर" और "कोड ट्रांसफ़ॉर्मेशन" की आवश्यकता होती है। इसलिए, यह एक बहुत सक्रिय खुला अनुसंधान क्षेत्र है जिसमें हर साल नए परिणाम दिखाई देते हैं।
    • क्योंकि अनुसंधान में लंबा समय लगता है, सॉफ्टवेयर लेखकों को कागज पर अनुकूलन को अंजाम देना होता है और अनुकूलित कोड को सॉफ्टवेयर में बदलना होता है। ट्रांसकोड कोड वास्तव में अनजाने में हो सकता है।
  2. बहुत निम्न स्तर का कोड।
      *

8

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

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


1
क्योंकि कंपाइलर उप-इष्टतम हैं (या प्रोग्रामिंग भाषा के नियम कुछ मान्यताओं या अनुकूलन का लाभ लेने से मना करते हैं), वास्तव में एक ओवरहेड है जिसे हटाया नहीं जा सकता है। इसके अलावा, कुछ अनुकूलन जैसे कि वैश्वीकरण में डेटा संगठन की आवश्यकताएं होती हैं (जैसे सरणी-संरचनाओं के बजाय संरचना-की-सरणियाँ) जो ओओपी या तो बढ़ा सकती हैं या बाधा डाल सकती हैं। (मैं हाल ही में सिर्फ एक std :: वेक्टर अनुकूलन कार्य पर काम किया है।)
rwong

5

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

आभासी कार्यों को कॉल करने के ओवरहेड के साथ इसका कोई लेना-देना नहीं है, और ऑप्टिमाइज़र / घबराना क्या करता है, इसके साथ बहुत कुछ नहीं करना है।

यह डेटा संरचनाओं के साथ सब कुछ करने के लिए है, जो कि सबसे अच्छा बिग-ओ प्रदर्शन करते हुए, बहुत खराब स्थिर कारक हैं। यह इस धारणा पर किया जाता है कि यदि ऐप में कोई प्रदर्शन-सीमित समस्या है, तो यह कहीं और है।

एक तरह से यह प्रकट होता है प्रति सेकंड नए की संख्या होती है , जिसे ओ (1) प्रदर्शन माना जाता है, लेकिन सैकड़ों से हजारों निर्देशों (मिलान हटाएं या जीसी समय सहित) को निष्पादित कर सकता है । इसका उपयोग वस्तुओं को बचाने के द्वारा किया जा सकता है, लेकिन यह कोड को "साफ" बनाता है।

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

हो सकता है कि दिए गए ऐप का प्रदर्शन लिखित रूप में ठीक हो।

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


3

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

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

आमतौर पर, निम्न-स्तरीय भाषा (या उच्च-स्तरीय भाषा के साथ चतुर चाल) का उपयोग करके आप जिस प्रकार के सुधार प्राप्त कर सकते हैं, वे निरंतर (रैखिक) समय में सुधार देते हैं, जो बड़े-ओह संकेतन के संदर्भ में आंकड़ा नहीं करते हैं। एल्गोरिथम सुधार के साथ आप गैर-रैखिक सुधार प्राप्त करने में सक्षम हो सकते हैं। वह अनमोल है।


1
+1: स्पेगेटी और ऑब्जेक्ट-ओरिएंटेड कोड (या एक अच्छी तरह से परिभाषित प्रतिमान में लिखे गए कोड) के बीच का अंतर है: अच्छे कोड के प्रत्येक संस्करण को फिर से समझने से समस्या में नई समझ आती है। स्पेगेटी पुनर्लेखन का प्रत्येक संस्करण कभी कोई अंतर्दृष्टि नहीं लाता है।
रवांग

@rwong को बेहतर नहीं बताया जा सकता है ;-)
umlcat 15

3

लेकिन क्या यह OOP प्रदर्शन के आधार पर सॉफ़्टवेयर के लिए नुकसान का कारण हो सकता है यानी प्रोग्राम कितनी तेज़ी से निष्पादित होता है?

अक्सर हाँ !!! परंतु...

दूसरे शब्दों में, कई अलग-अलग वस्तुओं के बीच कई संदर्भ हो सकते हैं, या कई वर्गों से कई तरीकों का उपयोग करने के परिणामस्वरूप "भारी" कार्यान्वयन हो सकता है?

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

जावा जैसी अन्य भाषाओं में, किसी वस्तु पर एक ओवरहेड होता है (अक्सर कई मामलों में काफी छोटा होता है, लेकिन वास्तव में नन्हा वस्तुओं के साथ कुछ दुर्लभ मामलों में खगोलीय)। उदाहरण के लिए, की Integerतुलना में काफी कम कुशल है int(64-बिट पर 4 के विपरीत 16 बाइट्स लेता है)। फिर भी यह सिर्फ अपव्यय या उस तरह का कुछ भी नहीं है। बदले में, जावा हर एक उपयोगकर्ता-परिभाषित प्रकार पर समान रूप से प्रतिबिंब के साथ-साथ किसी भी फ़ंक्शन को ओवरराइड करने की क्षमता को चिह्नित नहीं करता है final

फिर भी चलो सबसे अच्छा मामला लेते हैं: अनुकूलन C ++ कंपाइलर जो शून्य ओवरहेड के लिए ऑब्जेक्ट इंटरफेस को अनुकूलित कर सकता है । फिर भी, OOP अक्सर प्रदर्शन को नीचा दिखाता है और इसे चरम पर पहुंचने से रोकता है। यह एक पूर्ण विरोधाभास की तरह लग सकता है: यह कैसे हो सकता है? समस्या में निहित है:

इंटरफ़ेस डिजाइन और एनकैप्सुलेशन

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

इस उदाहरण को लें:

class Particle
{
public:
    ...

private:
    double birth;                // 8 bytes
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
    /*padding*/                  // 4 bytes of padding
};
Particle particles[1000000];     // 1mil particles (~24 megs)

मान लें कि हमारी मेमोरी एक्सेस पैटर्न केवल इन कणों के माध्यम से क्रमिक रूप से लूप करना है और स्क्रीन के कोनों को बंद करके और फिर परिणाम प्रदान करते हुए उन्हें प्रत्येक फ्रेम के चारों ओर बार-बार स्थानांतरित करना है।

पहले से ही हम एक शानदार 4 बाइट पैडिंग ओवरहेड को देख सकते हैं birthजब सदस्य को संयुक्ताक्षर रूप से एकत्र किया जाता है, तो सदस्य को ठीक से संरेखित करने के लिए आवश्यक है । पहले से ही ~ 16.7% मेमोरी संरेखण के लिए उपयोग किए गए मृत स्थान के साथ बर्बाद हो जाती है।

यह हमें बहुत बुरा लग सकता है क्योंकि हमारे पास इन दिनों घी की गीगाबाइट्स हैं। फिर भी हमारे पास आज भी सबसे ज्यादा पुरानी मशीनें अक्सर केवल 8 मेगाबाइट की होती हैं, जब यह CPU कैश (L3) के सबसे धीमे और सबसे बड़े क्षेत्र में आता है । जितना कम हम वहां फिट हो सकते हैं, उतना ही हम बार-बार DRAM की पहुंच के मामले में इसके लिए भुगतान करते हैं, और धीमी चीजें मिलती हैं। अचानक, 16.7% मेमोरी बर्बाद करना अब एक तुच्छ सौदे जैसा नहीं लगता।

हम क्षेत्र संरेखण पर किसी भी प्रभाव के बिना इस ओवरहेड को आसानी से समाप्त कर सकते हैं:

class Particle
{
public:
    ...

private:
    float x;                     // 4 bytes
    float y;                     // 4 bytes
    float z;                     // 4 bytes
};
Particle particles[1000000];     // 1mil particles (~12 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

अब हमने मेमोरी को 24 मीजी से घटाकर 20 मैग कर दिया है। एक अनुक्रमिक एक्सेस पैटर्न के साथ, मशीन अब इस डेटा का काफी तेजी से उपभोग करेगी।

लेकिन आइए इस birthक्षेत्र को थोड़ा और करीब से देखें। मान लीजिए कि यह प्रारंभिक समय रिकॉर्ड करता है जब एक कण पैदा होता है (बनाया जाता है)। कल्पना करें कि क्षेत्र केवल तब ही एक्सेस किया जाता है जब एक कण पहली बार बनाया जाता है, और हर 10 सेकंड में यह देखने के लिए कि क्या कण को ​​मरना चाहिए और स्क्रीन पर यादृच्छिक स्थान पर पुनर्जन्म हो सकता है। उस मामले में, birthएक ठंडा क्षेत्र है। यह हमारे प्रदर्शन-महत्वपूर्ण छोरों में पहुँचा नहीं है।

नतीजतन, वास्तविक प्रदर्शन-महत्वपूर्ण डेटा 20 मेगाबाइट नहीं है, लेकिन वास्तव में 12-मेगाबाइट सन्निहित ब्लॉक है। वास्तविक गर्म स्मृति जिसे हम अक्सर एक्सेस कर रहे हैं, उसका आकार आधा हो गया है ! हमारे मूल, 24-मेगाबाइट समाधान पर महत्वपूर्ण गति-अप की अपेक्षा करें (इसे मापने की आवश्यकता नहीं है - पहले से ही इस तरह का सामान एक हजार बार किया गया है, लेकिन संदेह होने पर स्वतंत्र महसूस करें)।

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

जब हम किसी एकल कण, एक एकल पिक्सेल, एक एकल पिक्सेल, यहां तक ​​कि एक 4-घटक वेक्टर, संभवतः एक भी "प्राणी" एक खेल में ऑब्जेक्ट की तरह, बहुत ही दानेदार वस्तु के इंटरफेस डिजाइन तक सीमित नहीं है, तो हम इष्टतम डेटा प्रतिनिधित्व को व्यक्त नहीं कर सकते , आदि चीता की गति व्यर्थ हो जाएगी यदि यह एक किशोर द्वीप पर खड़ा है जो 2 वर्ग मीटर है, और यह बहुत ही दानेदार वस्तु-उन्मुख डिजाइन है जो अक्सर प्रदर्शन के संदर्भ में करता है। यह उप-इष्टतम प्रकृति के डेटा प्रतिनिधित्व को सीमित करता है।

इसे और आगे ले जाने के लिए, मान लीजिए कि जब हम केवल कणों को घुमा रहे हैं, हम वास्तव में उनके x / y / z क्षेत्रों को तीन अलग-अलग छोरों में एक्सेस कर सकते हैं। उस मामले में, हम एवीएक्स रजिस्टरों के साथ सोए शैली के सिमड इंट्रिंसिक्स से लाभ उठा सकते हैं जो समानांतर में 8 एसपीएफपी संचालन को वेक्टर कर सकते हैं। लेकिन ऐसा करने के लिए, हमें अब इस प्रतिनिधित्व का उपयोग करना चाहिए:

float particle_x[1000000];       // 1mil particle X positions (~4 megs)
float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
double particle_birth[1000000];  // 1mil particle births (~8 bytes)

अब हम कण अनुकरण के साथ उड़ान भर रहे हैं, लेकिन हमारे कण डिजाइन का क्या हुआ। इसे पूरी तरह से ध्वस्त कर दिया गया है, और हम अब 4 समानांतर सरणियों को देख रहे हैं और जो भी उन्हें एकत्र करने के लिए कोई वस्तु नहीं है। हमारा ऑब्जेक्ट ओरिएंटेड Particleडिज़ाइन साओनारा चला गया है।

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

समाधान

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

फिर भी हम उस अंतिम निरूपण को ले सकते हैं जिस पर हम बसे थे और अभी भी एक वस्तु-उन्मुख इंटरफ़ेस को मॉडल करते हैं:

// Represents a collection of particles.
class ParticleSystem
{
public:
    ...

private:
    double particle_birth[1000000];  // 1mil particle births (~8 bytes)
    float particle_x[1000000];       // 1mil particle X positions (~4 megs)
    float particle_y[1000000];       // 1mil particle Y positions (~4 megs)
    float particle_z[1000000];       // 1mil particle Z positions (~4 megs)
};

अब हम अच्छे हैं। हम अपनी पसंद की सभी वस्तु-उन्मुख वस्तुएं प्राप्त कर सकते हैं। चीता के पास पूरे देश में जितनी तेजी से दौड़ सकता है, उतनी तेजी से दौड़ने के लिए है। हमारा इंटरफ़ेस अब हमें अड़चन के कोने में नहीं फँसाता है।

ParticleSystemसंभावित रूप से अमूर्त भी हो सकता है और आभासी कार्यों का उपयोग कर सकता है। यह अब बहुत बुरा है, हम प्रति-कण स्तर के बजाय कणों के स्तर के संग्रह में ओवरहेड के लिए भुगतान कर रहे हैं । ओवरहेड 1 / 1,000,000 वां है कि यह अन्यथा क्या होगा यदि हम व्यक्तिगत कण स्तर पर वस्तुओं को मॉडलिंग कर रहे थे।

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

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


बहुत खुबस। यह वही है जो मैं वास्तव में उच्च प्रदर्शन की मांग के साथ OOP के संयोजन के मामले में देख रहा था। मैं वास्तव में समझ नहीं पा रहा हूं कि इसे अधिक क्यों नहीं उकेरा गया है।
pbx

2

हां, ऑब्जेक्ट-ओरिएंटेड मानसिकता निश्चित रूप से तटस्थ या नकारात्मक हो सकती है जब यह एल्गोरिथम और कार्यान्वयन स्तर दोनों पर उच्च-प्रदर्शन प्रोग्रामिंग की बात आती है। यदि ओओपी एल्गोरिदम विश्लेषण की जगह लेता है, तो यह आपको समय से पहले कार्यान्वयन में ले जा सकता है और, न्यूनतम स्तर पर, ओओपी अमूर्त को अलग रखना होगा।

मुद्दा OOP के व्यक्तिगत उदाहरणों के बारे में सोचने पर जोर देने से है। मुझे लगता है कि यह कहना उचित है कि एल्गोरिथ्म के बारे में सोचने का ओओपी तरीका मूल्यों के एक विशिष्ट सेट के बारे में सोचकर और उस तरह से इसे लागू करना है। यदि यह आपका उच्चतम स्तर का मार्ग है, तो आपको एक परिवर्तन या पुनर्गठन का एहसास होने की संभावना नहीं है जो बिग ओ लाभ का कारण बनेगा।

एल्गोरिथम स्तर पर, यह अक्सर बड़ी ओ और लाभ के बीच मूल्यों और बाधाओं या रिश्तों के बारे में सोचता है जो बिग ओ लाभ को जन्म देते हैं। एक उदाहरण यह हो सकता है कि ओओपी मानसिकता में ऐसा कुछ भी नहीं है जो आपको एक लूप से "पूर्णांकों की एक सतत श्रेणी का योग" करने के लिए प्रेरित करेगा।(max + min) * n/2

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

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

बेशक, जैसा कि अधिकांश उत्तरों ने कहा है, अधिकांश विकास के लिए, अधिकांश एल्गोरिदम के लिए, ओओपी प्रदर्शन के लिए अप्रासंगिक है। जब तक आप "समय से पहले निराशा" नहीं करते हैं और बहुत सारे गैर-स्थानीय कॉल में जोड़ते हैं, तो thisपॉइंटर न तो यहां है और न ही है।


0

इसके संबंधित, और अक्सर अनदेखी की गई।

इसका आसान जवाब नहीं है, यह इस बात पर निर्भर करता है कि आप क्या करना चाहते हैं।

कुछ एल्गोरिदम सादे संरचित प्रोग्रामिंग का उपयोग करके प्रदर्शन में बेहतर हैं, जबकि अन्य, ऑब्जेक्ट ओरिएंटेशन का उपयोग करके बेहतर हैं।

ऑब्जेक्ट ओरिएंटेशन से पहले, कई स्कूल संरचित प्रोग्रामिंग के साथ एल्गोरिदम डिजाइन सिखाते हैं। आज, कई स्कूल, ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग सिखाते हैं, एल्गोरिथ्म डिज़ाइन और प्रदर्शन की अनदेखी करते हैं।

बेशक, वहाँ स्कूल जहां संरचित प्रोग्रामिंग सिखाते हैं, कि एल्गोरिदम के बारे में बिल्कुल भी परवाह नहीं है।


0

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

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

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


0

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


क्या आपका मतलब ओओ डिज़ाइन एक प्रक्रियात्मक भाषा, या ओओ डिज़ाइन और ओओ प्रोग्रामिंग भाषा के साथ लागू किया गया था?
umlcat

मैं एक C # एप्लिकेशन की बात कर रहा हूं। डिज़ाइन और भाषा दोनों OO हैं जहाँ भाषा का OO-iness कुछ छोटे प्रदर्शन हिट्स (वर्चुअल मेथड कॉल, ऑब्जेक्ट क्रिएशन, इंटरफ़ेस के माध्यम से मेंबर एक्सेस) को पेश करेगा, OO डिज़ाइन ने मुझे बहुत तेज़ एप्लिकेशन बनाने में मदद की। मैं क्या कहना चाहता हूं: ओओ (भाषा और डिजाइन) के कारण प्रदर्शन को भूल जाओ। जब तक आप लाखों पुनरावृत्तियों के साथ भारी गणना कर रहे हैं, OO आपको नुकसान नहीं पहुंचाएगा। जहाँ आप आमतौर पर I / O का समय बहुत ढीला करते हैं।
ओलिवियर जैकोट-डेसकोम्बर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.