क्या आपको लगता है कि "अच्छा" ऑब्जेक्ट ओरिएंटेड कोड लिखने और बहुत तेज़ी से कम विलंबता कोड लिखने के बीच एक व्यापार-बंद है? उदाहरण के लिए, C ++ / बहुरूपता के ओवरहेड आदि में वर्चुअल फ़ंक्शंस से बचना- री-राइटिंग कोड जो बुरा लग रहा है, लेकिन बहुत तेज़ है आदि?
मैं एक ऐसे क्षेत्र में काम करता हूं जो विलंबता की तुलना में थ्रूपुट पर थोड़ा अधिक केंद्रित है, लेकिन यह बहुत ही महत्वपूर्ण है, और मैं "सॉर्टा" कहूंगा ।
फिर भी एक समस्या यह है कि इतने सारे लोग अपने प्रदर्शन की धारणाओं को पूरी तरह से गलत मानते हैं। Novices अक्सर सब कुछ गलत हो जाता है, और "कम्प्यूटेशनल लागत" के उनके संपूर्ण वैचारिक मॉडल को पुन: काम करने की आवश्यकता होती है, केवल एल्गोरिथम जटिलता के बारे में केवल एक चीज है जो वे सही प्राप्त कर सकते हैं। इंटरमीडिएट में बहुत सारी चीजें गलत हो जाती हैं। विशेषज्ञों को कुछ चीजें गलत लगती हैं।
सटीक उपकरण है कि कैश मिसेज और शाखा गलतफहमी की तरह मैट्रिक्स प्रदान कर सकते हैं के साथ मापने क्या क्षेत्र में विशेषज्ञता के किसी भी स्तर के सभी लोगों को जांच में रखता है।
मापने का मतलब यह भी है कि ऑप्टिमाइज़ेशन न करने के क्या मायने हैं । विशेषज्ञ अक्सर नौसिखियों की तुलना में अनुकूलन में कम समय व्यतीत करते हैं , क्योंकि वे सही मापा हॉटस्पॉट्स का अनुकूलन कर रहे हैं और अंधेरे में जंगली छुरा का अनुकूलन करने की कोशिश नहीं कर रहे हैं, जो कि धीमी गति से हो सकता है (जो कि चरम रूप में, एक को माइक्रो-ऑप्टिमाइज़ कर सकते हैं कोडबेस में हर दूसरी पंक्ति के बारे में)।
प्रदर्शन के लिए डिजाइनिंग
उस तरफ से, प्रदर्शन के लिए डिजाइन करने की कुंजी डिजाइन भाग से आती है , जैसा कि इंटरफ़ेस डिज़ाइन में है। अनुभवहीनता के साथ समस्याओं में से एक यह है कि पूर्ण कार्यान्वयन मेट्रिक्स पर एक प्रारंभिक बदलाव होता है, जैसे कुछ सामान्यीकृत संदर्भ में अप्रत्यक्ष फ़ंक्शन कॉल की लागत, हालांकि लागत (जो बेहतर रूप से एक अनुकूलक के बिंदु से तत्काल समझ में आती है) देखने के बजाय एक देखने के बिंदु से) पूरे कोडबेस में इसे टालने का एक कारण है।
लागत सापेक्ष हैं । जबकि एक अप्रत्यक्ष फ़ंक्शन कॉल की लागत है, उदाहरण के लिए, सभी लागत सापेक्ष हैं। यदि आप उस लागत का भुगतान करने के लिए एक बार कॉल करते हैं जो लाखों तत्वों के माध्यम से बंद हो जाती है, तो इस लागत के बारे में चिंता करना बिलियन डॉलर के उत्पाद की खरीद के लिए पेनीज़ पर घंटे बिताने के समान है, केवल उस उत्पाद को खरीदने के लिए निष्कर्ष निकालना नहीं है क्योंकि यह एक पैसा भी महंगा था।
मोटे इंटरफ़ेस डिजाइन
प्रदर्शन का इंटरफ़ेस डिज़ाइन पहलू अक्सर इन लागतों को एक मोटे स्तर तक धकेलने के लिए पहले चाहता है। उदाहरण के लिए, एक कण के लिए रनटाइम अमूर्त लागत का भुगतान करने के बजाय, हम कण प्रणाली / उत्सर्जक के स्तर तक लागत को बढ़ा सकते हैं, प्रभावी ढंग से एक कण को कार्यान्वयन विस्तार और / या इस कण संग्रह के कच्चे डेटा में प्रदान कर सकते हैं।
तो ऑब्जेक्ट-ओरिएंटेड डिज़ाइन को प्रदर्शन के लिए डिज़ाइन के साथ असंगत नहीं होना पड़ता (चाहे विलंबता या थ्रूपुट), लेकिन ऐसी भाषा में प्रलोभन हो सकते हैं जो तेजी से नन्हा ग्रेन्युलर ऑब्जेक्ट्स मॉडल करने के लिए उस पर ध्यान केंद्रित करता है, और वहां नवीनतम ऑप्टिमाइज़र नहीं कर सकता है मदद। यह एक तरह से एकल बिंदु का प्रतिनिधित्व करने वाले वर्ग को समतल करने जैसी चीजें नहीं कर सकता है जो सॉफ्टवेयर के मेमोरी एक्सेस पैटर्न के लिए एक कुशल SoA प्रतिनिधित्व प्रदान करता है। मोटेपन के स्तर पर बनाए गए इंटरफ़ेस डिज़ाइन के साथ अंकों का एक संग्रह उस अवसर की पेशकश करता है, और आवश्यकतानुसार अधिक से अधिक इष्टतम समाधानों की ओर चलने की अनुमति देता है। इस तरह के डिजाइन को बल्क मेमोरी * के लिए डिज़ाइन किया गया है।
* ध्यान दें कि यहां मेमोरी पर ध्यान दें और डेटा पर नहीं , क्योंकि लंबे समय तक प्रदर्शन-महत्वपूर्ण क्षेत्रों में काम करने से डेटा प्रकार और डेटा संरचनाओं के बारे में आपका दृष्टिकोण बदल जाएगा और यह देखने के लिए कि वे मेमोरी से कैसे कनेक्ट होते हैं। बाइनरी सर्च ट्री अब केवल ऐसे मामलों में लॉगरिदमिक जटिलता के बारे में नहीं बनता है जब तक कि एक निश्चित आवंटनकर्ता द्वारा सहायता प्राप्त नहीं की जाती है। दृश्य एल्गोरिथम जटिलता को खारिज नहीं करता है, लेकिन यह अब इसे मेमोरी लेआउट के स्वतंत्र रूप से देखता है। स्मृति के पुनरावृत्तियों के बारे में अधिक होने के रूप में एक भी काम के पुनरावृत्तियों को देखना शुरू करता है। *
बहुत सारे प्रदर्शन-महत्वपूर्ण डिज़ाइन वास्तव में उच्च-स्तरीय इंटरफ़ेस डिज़ाइनों की धारणा के साथ बहुत संगत हो सकते हैं जो मनुष्यों को समझने और उपयोग करने में आसान हैं। अंतर यह है कि इस संदर्भ में "उच्च-स्तरीय" मेमोरी के थोक एकत्रीकरण के बारे में होगा, एक इंटरफ़ेस जो डेटा के संभावित बड़े संग्रह के लिए मॉडलिंग करता है, और हुड के तहत एक कार्यान्वयन के साथ जो काफी निम्न-स्तर हो सकता है। एक दृश्य सादृश्य एक कार हो सकती है जो वास्तव में आरामदायक और ड्राइव करने के लिए आसान है और ध्वनि की गति से चलते समय बहुत ही सुरक्षित है, लेकिन यदि आप हुड को पॉप करते हैं, तो अंदर थोड़ा अग्नि-साँस लेने वाले राक्षस हैं।
एक मोटे डिजाइन के साथ कोड में अधिक कुशल लॉकिंग पैटर्न प्रदान करने और समानता का फायदा उठाने के लिए एक आसान तरीका आता है (मल्टीथ्रेडिंग एक संपूर्ण विषय है जिसे मैं यहां छोड़ दूंगा)।
मेमोरी पूल
कम विलंबता प्रोग्रामिंग का एक महत्वपूर्ण पहलू संभवतः संदर्भ की स्थानीयता में सुधार के साथ-साथ स्मृति को आवंटित करने और डील करने की सामान्य गति में सुधार करने के लिए स्मृति पर एक बहुत स्पष्ट नियंत्रण होने वाला है। एक कस्टम एलोकेटर पूलिंग मेमोरी वास्तव में उसी तरह की डिजाइन मानसिकता को प्रतिध्वनित करती है जिसका हमने वर्णन किया था। यह थोक के लिए डिज़ाइन किया गया है ; यह एक मोटे स्तर पर डिज़ाइन किया गया है। यह बड़े ब्लॉकों में मेमोरी का प्रचार करता है और पहले से ही छोटे चंक्स में आवंटित मेमोरी को पूल करता है।
यह विचार महँगी चीज़ों को धकेलने के समान है (एक सामान्य प्रयोजन के आवंटन के खिलाफ एक मेमोरी चंक आवंटित करना, जैसे) एक मोटे और मोटे स्तर पर। एक मेमोरी पूल को बल्क में मेमोरी से निपटने के लिए डिज़ाइन किया गया है ।
टाइप सिस्टम अलग मेमोरी
किसी भी भाषा में दानेदार वस्तु-उन्मुख डिजाइन के साथ कठिनाइयों में से एक यह है कि यह अक्सर बहुत सारे उपयोगकर्ता-परिभाषित प्रकार और डेटा संरचनाओं को पेश करना चाहता है। यदि वे गतिशील रूप से आवंटित किए गए हैं तो वे प्रकार थोड़ा नन्हा चहक में आवंटित किए जा सकते हैं।
C ++ में एक सामान्य उदाहरण उन मामलों के लिए होगा जहां बहुरूपता की आवश्यकता होती है, जहां प्राकृतिक प्रलोभन एक सामान्य प्रयोजन स्मृति आवंटनकर्ता के खिलाफ एक उपवर्ग के प्रत्येक उदाहरण को आवंटित करना है।
यह सम्भवतया-सन्निहित स्मृति लेआउटों को छोटे-छोटे बिट-बिट्स और टुकड़ों में अलग करता हुआ टूटता है, जो कि एड्रेसिंग रेंज में बिखरे हुए हैं, जो अधिक पृष्ठ दोषों और कैश मिस में बदल जाता है।
सबसे कम-विलंबता, हकलाना-रहित, नियतात्मक प्रतिक्रिया की मांग करने वाले क्षेत्र संभवतः एक ही स्थान हैं जहाँ हॉटस्पॉट हमेशा एक ही अड़चन के लिए नहीं उबलते हैं, जहाँ छोटी अक्षमताएँ वास्तव में "जमा" होती हैं (बहुत सारे लोग कल्पना करते हैं गलत तरीके से एक प्रोफाइलर के साथ उन्हें जांच में रखने के लिए, लेकिन विलंबता संचालित क्षेत्रों में, वास्तव में कुछ दुर्लभ मामले हो सकते हैं जहां छोटी अक्षमताएं जमा होती हैं)। और इस तरह के संचय के सबसे सामान्य कारणों में से एक बहुत कुछ हो सकता है: सभी जगह स्मृति के नन्हे मुन्नों का अत्यधिक आवंटन।
जावा जैसी भाषाओं में, जब यह संभव हो int
, तो इसके बजाय टेंकलेंकी क्षेत्रों (तंग छोरों में संसाधित क्षेत्र) (जैसे अभी भी भारी उच्च-स्तरीय इंटरफ़ेस के पीछे ) के लिए सादे पुराने डेटा प्रकारों के अधिक सरणियों का उपयोग करने में मदद मिल सकती है, , ArrayList
उपयोगकर्ता परिभाषित Integer
वस्तुओं की। यह स्मृति अलगाव से बचा जाता है जो आम तौर पर उत्तरार्द्ध के साथ होता है। C ++ में, हमें संरचना को बहुत अधिक नीचा नहीं दिखाना है यदि हमारी मेमोरी आवंटन पैटर्न कुशल हैं, क्योंकि उपयोगकर्ता-परिभाषित प्रकारों को वहां और यहां तक कि एक सामान्य कंटेनर के संदर्भ में भी आवंटित किया जा सकता है।
फ्यूज़िंग मेमोरी बैक टुगेदर
यहां एक समाधान सजातीय डेटा प्रकारों के लिए एक कस्टम आवंटनकर्ता तक पहुंचने के लिए है, और संभवत: सजातीय डेटा प्रकारों के लिए भी। जब छोटे डेटा प्रकार और डेटा संरचनाएं बिट्स और बाइट्स के लिए स्मृति में समतल होती हैं, तो वे एक सजातीय प्रकृति (कुछ बदलती संरेखण आवश्यकताओं के साथ) लेते हैं। जब हम उन्हें मेमोरी-केंद्रित मानसिकता से नहीं देखते हैं, तो प्रोग्रामिंग भाषाओं का प्रकार "संभावित" को छोटे-छोटे बिखरे हुए विखंडू के अलावा संभावित-सन्निहित स्मृति क्षेत्रों को विभाजित / अलग करना चाहता है।
स्टैक इस से बचने के लिए इस मेमोरी-केंद्रित फोकस का उपयोग करता है और संभावित रूप से इसके अंदर उपयोगकर्ता-परिभाषित प्रकार के उदाहरणों के किसी भी संभव मिश्रित संयोजन को संग्रहीत करता है। स्टैक को अधिक उपयोग करना एक बहुत अच्छा विचार है जब संभव हो तो शीर्ष पर लगभग हमेशा एक कैश लाइन में बैठा होता है, लेकिन हम मेमोरी एलोकेटर्स को भी डिज़ाइन कर सकते हैं जो कि इन विशेषताओं में से कुछ को बिना LIFO पैटर्न के नकल करते हैं, स्मृति को असंगत डेटा प्रकारों में सन्निहित में टाइप करते हैं। यहां तक कि अधिक जटिल मेमोरी आवंटन और टैक्लोलेशन पैटर्न के लिए भी विखंडू।
आधुनिक हार्डवेयर को उसके चरम पर होने के लिए डिज़ाइन किया गया है, जब मेमोरी के सन्निहित ब्लॉक (बार-बार एक ही कैश लाइन, एक ही पृष्ठ, जैसे) तक पहुंचते हैं। वहाँ खोजशब्द सन्निहित है, क्योंकि यह केवल तभी लाभदायक है जब ब्याज के आसपास के डेटा हो। तो प्रदर्शन करने के लिए कुंजी (अभी तक कठिनाई) का एक बहुत फिर से एक साथ फिर से सन्निहित ब्लॉकों में स्मृति के अलग-अलग टुकड़े को फ्यूज करने के लिए है जो निष्कासन से पहले उनकी संपूर्णता (सभी आसपास के डेटा प्रासंगिक होने के कारण) तक पहुंच जाते हैं। प्रोग्रामिंग भाषाओं में विशेष रूप से उपयोगकर्ता-परिभाषित प्रकारों की समृद्ध प्रकार की प्रणाली यहां सबसे बड़ी बाधा हो सकती है, लेकिन हम हमेशा उचित आवंटन और / या भारी डिजाइन के माध्यम से समस्या को हल कर सकते हैं।
कुरूप
"बदसूरत" कहना मुश्किल है। यह एक व्यक्तिपरक मीट्रिक है, और कोई व्यक्ति जो एक बहुत ही प्रदर्शन-महत्वपूर्ण क्षेत्र में काम करता है, "ब्यूटी" के अपने विचार को बदलना शुरू कर देगा, जो कि बहुत अधिक डेटा-उन्मुख है और उन चीजों पर ध्यान केंद्रित करता है जो बल्क में चीजों को प्रोसेस करते हैं।
खतरनाक
"खतरनाक" आसान हो सकता है। सामान्य तौर पर, प्रदर्शन निचले स्तर के कोड की ओर पहुंचना चाहता है। उदाहरण के लिए, मेमोरी एलोकेटर को लागू करना, डेटा प्रकारों के नीचे पहुंचने और कच्चे बिट्स और बाइट्स के खतरनाक स्तर पर काम किए बिना असंभव है। नतीजतन, यह इन प्रदर्शन-महत्वपूर्ण उप-प्रणालियों में सावधानीपूर्वक परीक्षण प्रक्रिया पर ध्यान बढ़ाने में मदद कर सकता है, लागू किए गए अनुकूलन के स्तर के साथ परीक्षण की पूर्णता को मापता है।
सुंदरता
फिर भी यह सब कार्यान्वयन विस्तार स्तर पर होगा। एक अनुभवी बड़े पैमाने पर और प्रदर्शन-महत्वपूर्ण मानसिकता दोनों में, "सौंदर्य" कार्यान्वयन विवरणों के बजाय इंटरफ़ेस डिजाइनों की ओर स्थानांतरित हो जाता है। यह युग्मन और कैस्केडिंग टूटने के कारण कार्यान्वयन के बजाय "सुंदर", प्रयोग करने योग्य, सुरक्षित, कुशल इंटरफेस की तलाश करने के लिए एक उच्च प्राथमिकता बन जाता है जो कि इंटरफ़ेस डिज़ाइन परिवर्तन के चेहरे पर हो सकता है। कार्यान्वयन को किसी भी समय स्वैप किया जा सकता है। हम आम तौर पर आवश्यकतानुसार प्रदर्शन के लिए पुनरावृति करते हैं, और माप के अनुसार बताते हैं। पूरे सिस्टम को तोड़ने के बिना इस तरह के पुनरावृत्तियों के लिए जगह छोड़ने के लिए इंटरफ़ेस डिज़ाइन के साथ कुंजी एक मोटे स्तर पर मॉडल करना है।
वास्तव में, मेरा सुझाव है कि प्रदर्शन-महत्वपूर्ण विकास पर एक अनुभवी का ध्यान अक्सर सुरक्षा, परीक्षण, रखरखाव पर एक प्रमुख ध्यान केंद्रित करने के लिए होता है, सामान्य तौर पर एसई के शिष्य, क्योंकि बड़े पैमाने पर कोडबेस जिसमें प्रदर्शन का एक नंबर होता है -सिटिकल सबसिस्टम (पार्टिकल सिस्टम, इमेज प्रोसेसिंग एल्गोरिदम, वीडियो प्रोसेसिंग, ऑडियो फीडबैक, रेस्ट्रिअर्स, मेश इंजन इत्यादि) को रखरखाव के दुःस्वप्न में डूबने से बचने के लिए सॉफ्टवेयर इंजीनियरिंग पर पूरा ध्यान देने की आवश्यकता होगी। यह केवल एक संयोग नहीं है कि अक्सर सबसे आश्चर्यजनक रूप से कुशल उत्पादों में से सबसे कम संख्या में बग भी हो सकते हैं।
टी एल; डॉ
वैसे भी, इस विषय पर मेरी समझ है, वास्तव में प्रदर्शन-महत्वपूर्ण क्षेत्रों में प्राथमिकताओं से लेकर, क्या विलंबता को कम कर सकता है और छोटी अक्षमताओं को जमा कर सकता है, और वास्तव में "सुंदरता" (जब सबसे अधिक चीजों को देखते हुए) का गठन होता है।