क्या एक समय में एक को तार करना अकुशल है?


11

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

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


इसे कंपाइलर और प्रोफाइलर पर छोड़ दें, वे इसके बारे में परवाह करेंगे, आपका समय कंघी करने के लिए समय की तुलना में बहुत अधिक महंगा है।
OZ_

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

ध्यान दें कि स्ट्रिंग संघनन जैसी चीजें आमतौर पर एक लाइब्रेरी फ़ंक्शन द्वारा नियंत्रित की जाती हैं, न कि ऑपरेटिंग सिस्टम। ओएस मेमोरी आवंटन में शामिल हो सकता है, लेकिन शायद तार जैसी अपेक्षाकृत छोटी वस्तुओं के लिए नहीं।
कालेब

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

4
@Bizorke एक विशिष्ट परिदृश्य में, मैलोडॉक () (जो कि सी मानक लाइब्रेरी का हिस्सा है, ओएस नहीं) की तरह एक मेमोरी एलोकेटर का उपयोग मेमोरी से विभिन्न विखंडू को आवंटित करने के लिए किया जाता है जो पहले से ही ओएस द्वारा प्रक्रिया को आवंटित किया गया है। जब तक प्रक्रिया मेमोरी पर कम न हो जाए और अधिक अनुरोध करने की आवश्यकता न हो, ओएस को शामिल होने की आवश्यकता नहीं है। यदि पृष्ठ आवंटन में कोई दोष होता है तो यह निम्न स्तर पर भी हो सकता है। तो हां, OS अंततः मेमोरी प्रदान करता है, लेकिन यह जरूरी नहीं है कि प्रक्रिया के अंदर तार और अन्य वस्तुओं के टुकड़ों के आवंटन में शामिल हो।
कालेब

जवाबों:


21

आपकी व्याख्या क्यों यह अक्षम है, यह सटीक है, कम से कम उन भाषाओं से जो मैं (सी, जावा, सी #) से परिचित हूं, हालांकि मैं असहमत हूं कि बड़े पैमाने पर स्ट्रिंग संघनन का प्रदर्शन आम है। सी # कोड मैं पर काम में, वहाँ के प्रचुर उपयोग है StringBuilder, String.Formatआदि जो सभी स्मृति techiniques बचत ओवर-द पुनः आबंटन से बचने के लिए कर रहे हैं।

तो अपने प्रश्न का उत्तर पाने के लिए, हमें एक और प्रश्न पूछना चाहिए: यदि यह वास्तव में कभी भी मुद्दे को समाप्‍त करने का मुद्दा नहीं है, तो क्‍यों इसे पसंद करेंगे StringBuilderऔर StringBufferमौजूद रहेंगे ? ऐसी कक्षाओं का उपयोग अर्ध-शुरुआती प्रोग्रामिंग पुस्तकों और कक्षाओं में भी क्यों शामिल है? प्रतीत होता है कि पूर्व-परिपक्व अनुकूलन सलाह इतनी प्रमुख क्यों होगी?

यदि अधिकांश स्ट्रिंग-कॉन्फैनेटिंग डेवलपर्स अनुभव पर अपने उत्तर को शुद्ध रूप से आधार बनाते हैं, तो ज्यादातर कहेंगे कि इससे कभी कोई फर्क नहीं पड़ता है और "अधिक पठनीय" के पक्ष में ऐसे उपकरणों के उपयोग को दूर कर देगा for (int i=0; i<1000; i++) { strA += strB; }लेकिन उन्होंने इसे कभी नहीं मापा।

इस सवाल का असली जवाब इस एसओ उत्तर में पाया जा सकता है , जो बताता है कि एक उदाहरण में, जब 50,000 स्ट्रिंग्स (जो आपके आवेदन पर निर्भर करता है, एक सामान्य घटना हो सकती है), यहां तक ​​कि छोटे भी, एक 1000x प्रदर्शन हिट के परिणामस्वरूप ।

अगर प्रदर्शन का शाब्दिक अर्थ कुछ भी नहीं है, तो सभी तरीकों से दूर होना चाहिए। लेकिन मैं असहमत हूं कि विकल्प (StringBuilder) का उपयोग करना कठिन या कम पठनीय है , और इसलिए यह एक उचित प्रोग्रामिंग अभ्यास होगा जो "समय से पहले अनुकूलन" की रक्षा नहीं करना चाहिए।

अपडेट करें:

मुझे लगता है कि यह नीचे आता है, अपने मंच को जानता है और इसकी सर्वोत्तम प्रथाओं का पालन करता है, जो दुख की बात है कि सार्वभौमिक नहीं हैं । दो अलग-अलग "आधुनिक भाषाओं" से दो उदाहरण:

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

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


-1: प्रमुख बी.एस. strA + strBहै वास्तव में एक StringBuilder का उपयोग कर के रूप में ही। इसमें 1x प्रदर्शन हिट है। या 0x, आप कैसे माप रहे हैं इसके आधार पर। अधिक विवरण के लिए, कोडिंगहोरर
अमारा

5
@sparkleshy: मेरा अनुमान है कि SO उत्तर जावा का उपयोग करता है और आपका जुड़ा लेख C # का उपयोग करता है। मैं उन लोगों से सहमत हूं जो कहते हैं कि "कार्यान्वयन पर निर्भर करता है" और "इसे अपने विशेष वातावरण के लिए मापें"।
काई चान

1
@ कैचैन: स्ट्रिंग कॉन्फैक्शन मूल रूप से जावा और सी # में समान है
अमारा

3
@sparkleshy - पॉइंट लिया गया है, लेकिन स्ट्रिन्गबर्ल, स्ट्रिंग.जॉइन, आदि का उपयोग करने के लिए वास्तव में दो तारों को जोड़ना शायद ही कभी एक सिफारिश है। इसके अलावा, ओपी का सवाल विशेष रूप से " संग्रह की सामग्री को एक साथ शामिल होने " के संबंध में है , जो कि मामला नहीं है (जहां स्ट्रिंगबर्ल, आदि बहुत लागू है)। भले ही, मैं इस बिंदु पर अधिक होने के लिए अपने उदाहरण को अपडेट करूंगा।
केविन मैककॉर्मिक

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

2

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

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


1

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


3
मुझे लगता है कि बहुत प्रभावी नियम नहीं हैं।
OZ_

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

2
मैं कहना चाहिए कि माइकल ए जैक्सन एक ब्रिट, तो यह की थी अनुकूलन नहीं अनुकूलन । कुछ बिंदु पर मुझे वास्तव में विकिपीडिया पृष्ठ को सही करना चाहिए । * 8 ')
मार्क बूथ

मैं पूरी तरह से सहमत हूं, आपको उन वर्तनी त्रुटियों को ठीक करना चाहिए। हालांकि मेरी मूल भाषा क्वींस अंग्रेजी है, मैं यह आसान इंट्रा-वेब पर अमेरिका से बात करने लगता है .......
mattnz

कोई भी उपयोगकर्ताओं के बारे में नहीं सोचता। आप डेवलपर को बनाने के लिए इसे थोड़ा तेज़ कर सकते हैं, लेकिन फिर आपका हर एक ग्राहक इसके लिए पीड़ित होता है। उनके लिए अपना कोड लिखें, आपके लिए नहीं।
gbjbaanb

1

व्यावहारिक परीक्षण के बिना प्रदर्शन के बारे में कुछ भी कहना बहुत कठिन है। हाल ही में मुझे यह जानकर बहुत हैरानी हुई कि जावास्क्रिप्ट में आमतौर पर एक भोले के तार की सघनता आम तौर पर अनुशंसित "मेक लिस्ट एंड जॉइन" सॉल्यूशन से अधिक तेज होती है ( यहां परीक्षण करें , t1 की तुलना t4 से करें)। मैं अभी भी हैरान हूं कि ऐसा क्यों होता है।

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

  1. मेरा इनपुट कितना बड़ा है?

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

  2. मेरा कंपाइलर कितना स्मार्ट है?

    कई कंपाइलर स्मार्ट हैं जो कि "वेरिएबल दूर" वेरिएबल को लिखे जाते हैं, लेकिन कभी पढ़े नहीं जाते। इसी तरह, एक अच्छा संकलक भी एक (कोर) पुस्तकालय उपयोग के लिए एक भोले स्ट्रिंग संघनन में परिवर्तित करने में सक्षम हो सकता है और, यदि उनमें से कई बिना किसी पढ़े बने हैं, तो उन कार्यों के बीच इसे वापस स्ट्रिंग में बदलने की कोई आवश्यकता नहीं है (भले ही आपका स्रोत कोड बस ऐसा करने के लिए लगता है)। मैं यह नहीं बता सकता कि वहां कोई कंपाइलर ऐसा करता है या नहीं, या किस हद तक किया जाता है (AFAIK Java कम से कम एक ही अभिव्यक्ति में कई स्ट्रिंग को StringBuffer ऑपरेशंस के अनुक्रम में बदल देता है), लेकिन यह एक संभावना है।

  3. मेरा रनटाइम मेमोरी कैसे प्रबंधित करता है?

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

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

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


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

इस उत्तर की जांच करें , जावा कंपाइलर पहले से ही StringBuilderहुड के तहत उपयोग करता है , यह toStringतब तक करना होगा जब तक कि चर वास्तव में जरूरत न हो। यदि मैं सही ढंग से याद करता हूं, तो यह एक ही अभिव्यक्ति के लिए करता है, मेरा एकमात्र संदेह यह है कि क्या यह एक ही विधि में कई बयानों पर लागू होता है या नहीं। मुझे .NET इंटर्नल्स के बारे में कुछ नहीं पता है, लेकिन मेरा मानना ​​है कि सी # कंपाइलर द्वारा भी एक समान रणनीति नियोजित की जा सकती है।
mgibsonbr

0

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


-1

क्या एक समय में एक को तार करना अकुशल है?

नहीं।

क्या आपने 'द सैड ट्रेजेडी ऑफ़ माइक्रो-ऑप्टिमाइज़ेशन थिएटर' पढ़ा है ?


4
"सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है।" - नुथ
स्कॉट सी विल्सन

4
अनुकूलन में सभी बुराई की जड़ इस वाक्यांश को संदर्भ के बिना ले रही है।
OZ_

बस कुछ समर्थन कारणों के बिना इस तरह से एक मंच पर उपयोगी नहीं है कह कुछ सच है।
एडवर्ड स्ट्रेंज

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