तार इतने धीमे क्यों हैं?


23

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


11
यदि आप जानते हैं कि ये "औसत संचालन" पौराणिक हैं, तो क्या आप कम से कम हमें बता सकते हैं कि उनमें से कुछ क्या हैं? यह देखते हुए कि आप इस तरह के अस्पष्ट सवाल पूछ रहे हैं, आपके दावे पर भरोसा करना कठिन है कि ये अनिर्दिष्ट ऑपरेशन वास्तव में पौराणिक हैं।
सेह

1
@ हाँ, दुर्भाग्य से, मैं वास्तव में इसका जवाब नहीं दे सकता। कई बार मैंने वास्तव में लोगों से पूछा है कि स्ट्रिंग्स की तुलना में धीमी क्या है, वे सिर्फ एक प्रकार की झाड़ी हैं और कहते हैं "वे अभी धीमी हैं।" इसके अलावा, अगर मेरे पास अधिक विशिष्ट जानकारी थी, तो यह एसओ के लिए एक प्रश्न होगा, न कि प्रोग्रामर; यह पहले से ही थोड़े सीमावर्ती है।
पोप्स

मुद्दा क्या है ? अगर कहा गया कि तार वास्तव में धीमे हैं, तो क्या आप उनका उपयोग बंद कर देंगे?
ट्यूलेंस कोर्डोवा

रहने भी दो। अगर कोई आपको इस तरह की बकवास बताता है, तो प्रतिवाद यह है: "वास्तव में? क्या वे हैं? क्या हमें एक अंतर-सरणी का उपयोग करना चाहिए?"
इंगो

जवाबों:


47

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

उदाहरण के लिए, दो संख्याओं को जोड़ने पर सामान्यतः 2-4 ASM निर्देश लगते हैं। समवर्ती ("जोड़ना") दो तारों को एक नई मेमोरी आवंटन की आवश्यकता होती है और पूरे स्ट्रिंग को शामिल करते हुए एक या दो स्ट्रिंग प्रतियां होती हैं।

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


4
और कुछ भाषाएं इसे बहुत बेहतर बनाती हैं: सरणी की शुरुआत में डेल्फी की स्ट्रिंग की लंबाई का एन्कोडिंग स्ट्रिंग का संघनन बहुत तेज करता है।
फ्रैंक शीयर

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

4
@mathepic: हाँ, और जहाँ तक यह आपको ले जाएगा, उसके लिए ठीक है, लेकिन जब आप libc या अन्य बाहरी कोड के साथ बातचीत करना शुरू करते हैं, तो यह उम्मीद करता है कि a char*, not a strbuf, और आप वापस वर्ग 1 में आ गए हैं। केवल इतना ही आप हैं एक बुरा डिजाइन भाषा में पके हुए है जब कर सकते हैं।
मेसन व्हीलर

6
@mathepic: बेशक bufसूचक के वहाँ है। मेरा मतलब कभी नहीं था कि यह उपलब्ध नहीं है; बल्कि, यह आवश्यक है। कोई भी कोड जो आपके अनुकूलित-लेकिन-गैर-मानक स्ट्रिंग प्रकार के बारे में नहीं जानता है, जिसमें मानक लाइब्रेरी जैसी मूलभूत चीजें शामिल हैं , फिर भी धीमी, असुरक्षित पर वापस गिरना पड़ता है char*। आप चाहें तो उस FUD को कॉल कर सकते हैं, लेकिन यह सच नहीं है।
मेसन व्हीलर

7
लोग, फ्रैंक शीयर की बात के बारे में एक जोएल स्पॉल्स्की कॉलम है: बैक टू बेसिक्स
user16764

14

यह एक पुराना धागा है और मुझे लगता है कि अन्य उत्तर महान हैं, लेकिन कुछ को नजरअंदाज करते हैं, इसलिए यहां मेरे (देर से) 2 सेंट हैं।

सिंथेटिक चीनी-कोटिंग की जटिलता को छुपाता है

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

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

कार्यान्वयन का विवरण

अच्छा ओल 'ऐरे

इस अंतर्निहित "जटिलता" के तत्वों में से एक यह है कि अधिकांश स्ट्रिंग कार्यान्वयन स्ट्रिंग का प्रतिनिधित्व करने के लिए कुछ सन्निहित स्मृति स्थान के साथ एक सरल डेटा-संरचना का उपयोग करने का सहारा लेंगे: आपका अच्छा ol 'सरणी।

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

यहां तक ​​कि स्ट्रिंग के आकार को लौटाना महंगा हो सकता है, अगर आपकी भाषा स्ट्रिंग की लंबाई को कैश नहीं करती है और वर्णों को गिनने के लिए इसे चलाने की आवश्यकता है।

इसी तरह के कारणों के लिए, अपने स्ट्रिंग में तत्वों को जोड़ना महंगा साबित होगा क्योंकि आपको इस ऑपरेशन के लिए कुछ मेमोरी को फिर से आवंटित करने की आवश्यकता होगी।

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

यूनिकोड समर्थन

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


इन सबका परिणाम यह है कि जब आप छद्म कोड के समकक्ष कुछ करते हैं:

hello = "hello,"
world = " world!"
str = hello + world

यह नहीं हो सकता है - भाषा के विकासकर्ताओं ने उन सभी बेहतरीन प्रयासों के बावजूद, जैसा कि आप को छोड़कर उन्हें व्यवहार में रखा है - एक सरल रूप में:

a = 1;
b = 2;
shouldBeThree = a + b

अनुवर्ती के रूप में, आप पढ़ना चाह सकते हैं:


वर्तमान चर्चा के लिए अच्छा इसके अलावा।
हाबिल

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

@Abel: धन्यवाद, मुझे ऐसा लगा कि यह अधिक सामान्य विवरणों के लिए जगह है।

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

1

वाक्यांश "औसत संचालन" संभवतः एक सैद्धांतिक रैंडम-एक्सेस स्टोर-प्रोग्राम मशीन के एकल संचालन के लिए शॉर्टहैंड है । यह सैद्धांतिक मशीन है जो विभिन्न एल्गोरिदम के चलने के समय का विश्लेषण करने के लिए उपयोग करने के लिए प्रथागत है।

सामान्य संचालन को लोड, जोड़, घटाना, स्टोर, शाखा के रूप में लिया जाता है। शायद यह भी पढ़ें, प्रिंट करें और रोकें।

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


1

यह पूरी तरह से ऑपरेशन पर निर्भर करता है, कैसे तार का प्रतिनिधित्व किया जाता है, और क्या अनुकूलन मौजूद हैं। यदि तार 4 या 8 बाइट लंबाई (और संरेखित) हैं, तो वे आवश्यक रूप से धीमे नहीं होंगे - कई ऑपरेशन आदिम के समान तेज़ होंगे। या, यदि सभी तारों में 32-बिट या 64-बिट हैश है, तो कई ऑपरेशन भी उतनी ही तेजी से होंगे (हालांकि आप हैशिंग लागत का भुगतान करते हैं)।

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


0

मुझे एक सवाल के साथ अपने सवाल का जवाब दें। एक शब्द कहने की तुलना में शब्दों की एक स्ट्रिंग को अधिक समय क्यों लगता है?


2
यह जरूरी नहीं है।
user16764

3
Supercalifragilisticexpialidocious
Spoike

s / शब्द / शब्दांश / छ
कालेब

मुझे अपने सवाल का जवाब एक सवाल के साथ दें: आप यह क्यों नहीं कहते हैं कि आपके जवाब का मतलब क्या है? यह सब के बाद, स्पष्ट है कि इसे कुछ रन-टाइम सिस्टम पर लागू करने के रूप में कैसे व्याख्या की जा सकती है।
PJTraill
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.