यहां कुछ अच्छे उदाहरण हैं, लेकिन मैं कुछ व्यक्तिगत लोगों के साथ कूदना चाहता था जहां अपरिवर्तनीयता ने एक टन की मदद की। मेरे मामले में, मैंने मुख्य रूप से ओवरलैपिंग रीड और राइट के साथ समानांतर रूप से कोड चलाने में सक्षम होने और दौड़ की स्थिति के बारे में चिंता न करने की उम्मीद के साथ एक अपरिवर्तनीय समवर्ती डेटा संरचना डिजाइन करना शुरू कर दिया। एक बात थी जो जॉन कार्मैक ने मुझे उस तरह की प्रेरणा दी, जिससे वह इस तरह के विचार के बारे में बात कर सके। यह इस तरह लागू करने के लिए एक बहुत ही बुनियादी संरचना और बहुत तुच्छ है:
निश्चित रूप से इसमें कुछ और घंटियाँ और सीटी बजती हैं, जैसे कि लगातार समय में तत्वों को निकालने में सक्षम होना और पीछे हटने योग्य छिद्रों को छोड़ना और ब्लॉक हो गए हैं यदि वे खाली हो जाते हैं और संभावित रूप से किसी अपरिवर्तनीय उदाहरण के लिए मुक्त हो जाते हैं। लेकिन मूल रूप से संरचना को संशोधित करने के लिए, आप एक "क्षणिक" संस्करण को संशोधित करते हैं और एक नई अपरिवर्तनीय प्रतिलिपि प्राप्त करने के लिए अपने द्वारा किए गए परिवर्तनों को कम से कम करते हैं, जो पुराने को नहीं छूता है, नए संस्करण के साथ केवल ब्लॉकों की नई प्रतियां बनाई जाती हैं उथली नकल करते हुए और दूसरों को गिनते हुए संदर्भ को अद्वितीय बनाया जाना चाहिए।
हालांकि, मैं यह नहीं मिला है किबहुआयामी उद्देश्यों के लिए उपयोगी। आखिरकार, अभी भी वैचारिक समस्या है जहां, कहते हैं, एक भौतिकी प्रणाली समवर्ती रूप से भौतिकी को लागू करती है जबकि एक खिलाड़ी दुनिया में तत्वों को स्थानांतरित करने की कोशिश कर रहा है। ट्रांसफ़ॉर्म किए गए डेटा की कौन सी अपरिवर्तनीय प्रतिलिपि आपके साथ जाती है, एक खिलाड़ी जो रूपांतरित होता है या एक फिजिक्स सिस्टम ट्रांसफ़ॉर्म किया जाता है? इसलिए मुझे वास्तव में इस बुनियादी वैचारिक समस्या का एक अच्छा और सरल समाधान नहीं मिला है सिवाय परस्पर डेटा संरचनाओं के जो कि एक स्मार्ट तरीके से लॉक होते हैं और ओवरलैपिंग को हतोत्साहित करते हैं और स्टडिंग थ्रेड्स से बचने के लिए बफर के एक ही सेक्शन को लिखते हैं। ऐसा कुछ जॉन कार्मैक को लगता है कि संभवतः उसे अपने खेल में हल करने के लिए पता चला है; कम से कम वह इसके बारे में बात करता है जैसे वह कीड़े के एक कार को खोलने के बिना लगभग एक समाधान देख सकता है। मैं उस संबंध में उससे दूर नहीं गया हूं। मैं देख सकता हूँ सभी अंतहीन सवाल हैं अगर मैं बस के आसपास सब कुछ समानांतर की कोशिश की। काश, मैं एक दिन उनके मस्तिष्क पर उठाता, क्योंकि मेरे अधिकांश प्रयास उन विचारों के साथ शुरू होते थे, जिन्हें वह फेंक देते थे।
फिर भी, मुझे अन्य क्षेत्रों में इस अपरिवर्तनीय डेटा संरचना का भारी मूल्य मिला । मैं अब भी इसका उपयोग उन छवियों को संग्रहीत करने के लिए करता हूं जो वास्तव में अजीब हैं और यादृच्छिक-अभिगम के लिए कुछ और निर्देशों (दाएं पारी और and
सूचक की एक परत के साथ सूचक) की आवश्यकता होती है, लेकिन मैं नीचे दिए गए लाभों को कवर करूंगा।
सिस्टम को पूर्ववत करें
सबसे अधिक तात्कालिक स्थानों में से एक जो मुझे फायदा हुआ वह पूर्ववत प्रणाली थी। पूर्व प्रणाली कोड मेरे क्षेत्र (विज़ुअल एफएक्स उद्योग) में सबसे अधिक त्रुटि वाली चीजों में से एक हुआ करता था, और न केवल उन उत्पादों पर, जिन पर मैंने काम किया था, लेकिन प्रतिस्पर्धी उत्पादों में (उनके पूर्ववत सिस्टम भी परतदार थे) क्योंकि इतने अलग थे डेटा को पूर्ववत करने और ठीक से पुन: प्रसारित करने के बारे में चिंता करने के लिए (संपत्ति प्रणाली, मेष डेटा परिवर्तन, shader परिवर्तन जो गुण-आधारित नहीं थे, एक दूसरे के साथ स्वैप करने की तरह, दृश्य पदानुक्रम परिवर्तन जैसे बच्चे के माता-पिता को बदलना, छवि / बनावट परिवर्तन आदि आदि)।
इसलिए पूर्ववत किए गए कोड की मात्रा बहुत अधिक थी, अक्सर कोड को लागू करने की प्रणाली को लागू करने की मात्रा के प्रतिद्वंद्वी होते हैं, जिसके लिए पूर्ववत स्थिति को राज्य परिवर्तनों को रिकॉर्ड करना पड़ता था। इस डेटा संरचना पर झुकाव से, मैं पूर्ववत प्रणाली को केवल इस तक लाने में सक्षम था:
on user operation:
copy entire application state to undo entry
perform operation
on undo/redo:
swap application state with undo entry
आम तौर पर जब आपके दृश्य डेटा को पूरी तरह से कॉपी करने के लिए गीगाबाइट का विस्तार होता है, तो ऊपर का कोड काफी अक्षम होगा। लेकिन यह डेटा संरचना केवल उथली प्रतियों को कॉपी करती है, जिन्हें बदला नहीं गया था, और इसने इसे वास्तव में काफी सस्ते में पूरे एप्लिकेशन राज्य की एक अपरिवर्तनीय प्रतिलिपि बना दिया था। इसलिए अब मैं पूर्ववत कोड के रूप में आसानी से पूर्ववत प्रणालियों को लागू कर सकता हूं और इस अपरिवर्तनीय डेटा संरचना का उपयोग करने पर ध्यान केंद्रित कर सकता हूं ताकि एप्लिकेशन स्टेट के अपरिवर्तित भागों को सस्ता और सस्ता और सस्ता बनाया जा सके। जब से मैंने इस डेटा संरचना का उपयोग करना शुरू किया है, मेरी सभी व्यक्तिगत परियोजनाओं में इस सरल पैटर्न का उपयोग करते हुए पूर्ववत सिस्टम हैं।
अब भी यहाँ कुछ ओवरहेड है। पिछली बार जब मैंने मापा था कि यह लगभग 10 किलोबाइट था, तो इसे लागू करने के लिए बिना किसी बदलाव के पूरे आवेदन राज्य की नकल करना (यह दृश्य की जटिलता से स्वतंत्र है क्योंकि दृश्य एक पदानुक्रम में व्यवस्थित है, इसलिए यदि जड़ से नीचे कुछ भी नहीं बदलता है, केवल जड़ है बच्चों में नीचे उतरने के बिना उथले की नकल की जाती है)। यह 0 बाइट्स से बहुत दूर है क्योंकि एक पूर्ववत व्यवस्था के लिए केवल डेल्टास के भंडारण की आवश्यकता होगी। लेकिन प्रति ऑपरेशन 10 किलोवॉट के ओवरहेड पर, यह अभी भी प्रति 100 उपयोगकर्ता संचालन में केवल मेगाबाइट है। इसके अलावा मैं अभी भी संभावित रूप से स्क्वाश कर सकता हूं ताकि भविष्य में जरूरत पड़ने पर और नीचे पहुंच सके।
अपवाद-सुरक्षा
एक जटिल अनुप्रयोग के साथ अपवाद-सुरक्षा कोई तुच्छ मामला नहीं है। हालाँकि, जब आपकी एप्लिकेशन स्थिति अपरिवर्तनीय है और आप केवल परमाणु परिवर्तन लेनदेन करने की कोशिश करने के लिए क्षणिक वस्तुओं का उपयोग कर रहे हैं, तो यह स्वाभाविक रूप से अपवाद-सुरक्षित है क्योंकि यदि कोड का कोई भी हिस्सा फेंकता है, तो एक नई अपरिवर्तनीय प्रतिलिपि देने से पहले क्षणिक को हटा दिया जाता है । ताकि मैं हमेशा एक जटिल सी ++ कोडबेस में सही पाने के लिए सबसे कठिन चीजों में से एक को तुच्छ समझता हूं।
बहुत से लोग अक्सर C ++ में RAII के अनुरूप संसाधनों का उपयोग करते हैं और सोचते हैं कि यह अपवाद-सुरक्षित होने के लिए पर्याप्त है। अक्सर ऐसा नहीं होता है, क्योंकि एक फ़ंक्शन आम तौर पर अपने दायरे के स्थानीय लोगों से परे राज्यों को दुष्प्रभाव पैदा कर सकता है। आपको आम तौर पर उन मामलों में स्कोप गार्ड और परिष्कृत रोलबैक लॉजिक के साथ काम करना शुरू करना होगा। इस डेटा संरचना ने इसे बनाया है इसलिए मुझे अक्सर इसके साथ परेशान होने की आवश्यकता नहीं है क्योंकि फ़ंक्शन साइड इफेक्ट का कारण नहीं हैं। वे आवेदन की स्थिति को बदलने के बजाय आवेदन राज्य की अपरिवर्तनीय प्रतियाँ लौटा रहे हैं।
गैर-विनाशकारी संपादन
गैर-विनाशकारी संपादन मूल उपयोगकर्ता के डेटा (बस इनपुट डेटा और आउटपुट डेटा को छूने के बिना इनपुट) को छूने के बिना एक साथ लेयरिंग / स्टैकिंग / कनेक्टिंग ऑपरेशन है। यह आमतौर पर फ़ोटोशॉप की तरह एक साधारण छवि अनुप्रयोग के साथ लागू करने के लिए तुच्छ है और इस डेटा संरचना से इतना लाभ नहीं हो सकता है क्योंकि कई ऑपरेशन बस पूरी छवि के प्रत्येक पिक्सेल को बदलना चाहते हैं।
हालांकि, गैर-विनाशकारी मेष संपादन के साथ, उदाहरण के लिए, बहुत सारे ऑपरेशन अक्सर मेष के केवल एक हिस्से को बदलना चाहते हैं। एक ऑपरेशन बस कुछ कोने को यहां स्थानांतरित करना चाह सकता है। एक और सिर्फ वहाँ कुछ बहुभुज को वश में करना चाहते हो सकता है। यहां अपरिवर्तनीय डेटा संरचना एक टन को पूरे जाल की एक पूरी प्रतिलिपि बनाने की आवश्यकता से बचने में मदद करती है बस जाल के एक नए हिस्से को बदलने के लिए इसका नया संस्करण वापस करने के लिए।
कम से कम साइड इफेक्ट
हाथ में इन संरचनाओं के साथ, यह उन कार्यों को लिखना भी आसान बनाता है जो इसके लिए एक बड़ा प्रदर्शन जुर्माना लगाए बिना दुष्प्रभावों को कम करते हैं। मैंने खुद को अधिक से अधिक कार्यों को लिखते हुए पाया है, जो इन दिनों पूरी तरह से अपरिवर्तनीय डेटा संरचनाओं को बिना साइड इफ़ेक्ट के वापस कर देता है, भले ही वह थोड़ा बेकार लगता हो।
उदाहरण के लिए, आमतौर पर पदों का एक गुच्छा बदलने का प्रलोभन एक मैट्रिक्स और वस्तुओं की एक सूची को स्वीकार करने और एक परिवर्तनशील फैशन में बदलने के लिए हो सकता है। इन दिनों मैं खुद को सिर्फ वस्तुओं की एक नई सूची में वापस पाता हूं।
जब आपके सिस्टम में इस तरह के अधिक कार्य होते हैं जो बिना किसी दुष्प्रभाव का कारण बनते हैं, तो निश्चित रूप से इसे सही करने के बारे में तर्क करने के साथ-साथ इसकी शुद्धता का परीक्षण करना आसान बनाता है।
सस्ते कॉपियों के लाभ
तो वैसे भी, ये ऐसे क्षेत्र हैं जहां मुझे अपरिवर्तनीय डेटा संरचनाओं (या लगातार डेटा संरचनाओं) का सबसे अधिक उपयोग मिला। मुझे भी शुरू में थोड़ा अटपटा लगा और एक अपरिवर्तनीय पेड़ और अपरिवर्तनीय लिंक्ड सूची और अपरिवर्तनीय हैश तालिका बनाई गई, लेकिन समय के साथ मैंने शायद ही कभी उन लोगों के लिए अधिक उपयोग पाया। मैंने मुख्य रूप से ऊपर चित्र में चंकी अपरिवर्तनीय सरणी-जैसे कंटेनर का सबसे अधिक उपयोग पाया।
मेरे पास अभी भी बहुत सारे कोड हैं जो म्यूटेबल्स के साथ काम कर रहे हैं (इसे कम से कम स्तर के कोड के लिए व्यावहारिक आवश्यकता पाते हैं), लेकिन मुख्य एप्लिकेशन स्टेट एक अपरिवर्तनीय पदानुक्रम है, जो एक अपरिवर्तनीय दृश्य से इसके अंदर अपरिवर्तनीय घटकों तक ड्रिलिंग करता है। कुछ सस्ते घटकों को अभी भी पूर्ण रूप से कॉपी किया जाता है, लेकिन सबसे महंगे हैं जैसे कि मेष और चित्र केवल उन हिस्सों की आंशिक सस्ती प्रतियों को बदलने के लिए अपरिवर्तनीय संरचना का उपयोग करते हैं जिन्हें बदलने की आवश्यकता थी।
ConcurrentModificationException
जो आमतौर पर एक ही धागे में एक ही धागे में संग्रह को उत्परिवर्तित करने के कारण होता है, एक ही संग्रह मेंforeach
लूप के शरीर में ।