क्या अपरिवर्तनीयता मल्टी-प्रोसेसर प्रोग्रामिंग में ताले की आवश्यकता को पूरी तरह से समाप्त कर देती है?


39

भाग 1

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

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

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

  • आई / ओ
  • अपवाद / त्रुटियों
  • अन्य भाषाओं में लिखे गए कार्यक्रमों के साथ सहभागिता
  • अन्य मशीनों (भौतिक, आभासी या सैद्धांतिक) के साथ सहभागिता

@JimmaHoffa को उनकी टिप्पणी के लिए विशेष धन्यवाद जिसने यह प्रश्न शुरू किया!

भाग 2

मल्टी-प्रोसेसर प्रोग्रामिंग का उपयोग अक्सर अनुकूलन तकनीक के रूप में किया जाता है - कुछ कोड को तेजी से चलाने के लिए। जब तात्कालिक बनाम अपरिवर्तनीय वस्तुओं का उपयोग करना तेजी से होता है?

Amdahl के कानून में निर्धारित सीमा को देखते हुए , जब आप अपरिवर्तनीय वस्तुओं बनाम लॉकिंग म्यूटेबल के साथ बेहतर ओवर-ऑल परफॉरमेंस (खाते में लिया गया कचरा कलेक्टर के साथ या बिना) प्राप्त कर सकते हैं?

सारांश

मैं इन दो प्रश्नों को एक में जोड़ रहा हूं, जहां पर थ्रेडिंग बॉक्स समस्याओं के समाधान के रूप में इम्मुटिबिलिटी के लिए है।


21
but everything has a side effect- उह, नहीं, यह नहीं है। एक फ़ंक्शन जो कुछ मान को स्वीकार करता है और कुछ अन्य मान लौटाता है, और फ़ंक्शन के बाहर कुछ भी परेशान नहीं करता है, इसका कोई दुष्प्रभाव नहीं है, और इसलिए यह थ्रेड-सुरक्षित है। इससे कोई फर्क नहीं पड़ता कि कंप्यूटर बिजली का उपयोग करता है। यदि आप चाहें तो हम कॉस्मिक किरणों के बारे में भी बात कर सकते हैं, जो कि मेमोरी सेल्स को मारते हैं, लेकिन तर्क को व्यावहारिक रखें। यदि आप चीजों पर विचार करना चाहते हैं कि फ़ंक्शन किस तरह से बिजली की खपत को प्रभावित करता है, तो यह थ्रेडसेफ़ प्रोग्रामिंग की तुलना में एक अलग समस्या है।
रॉबर्ट हार्वे

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

1
आप वास्तव में यह के माध्यम से प्राप्त कर सकते हैं, मैं आपके सवाल का इस कुख्यात कागज के दिल को जाता है लगता है research.microsoft.com/en-us/um/people/simonpj/papers/...
जिमी हौफा

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

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

जवाबों:


35

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

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

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

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

प्रदर्शन के लिए, यह आपके ऐप पर निर्भर करता है। ताले (आमतौर पर) भारी होते हैं। अन्य संगामिति प्रबंधन तंत्र तेज़ हैं लेकिन आपके डिज़ाइन पर उच्च प्रभाव डालते हैं। सामान्य तौर पर , एक उच्च समवर्ती डिजाइन जो अपरिवर्तनीय वस्तुओं का उपयोग करता है (और उनकी कमजोरियों से बचा जाता है) एक उच्च समवर्ती डिजाइन की तुलना में बेहतर प्रदर्शन करेगा जो कि उत्परिवर्तित वस्तुओं को लॉक करता है। यदि आपका कार्यक्रम हल्के ढंग से समवर्ती है, तो यह निर्भर करता है और / या इससे कोई फर्क नहीं पड़ता।

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

इसलिए योग करने के लिए: अपरिवर्तनीयता मदद करती है लेकिन सही ढंग से संगामिति को संभालने के लिए आवश्यक चुनौतियों को समाप्त नहीं करेगी। यह मदद करने के लिए व्यापक हो जाता है, लेकिन सबसे बड़ा लाभ प्रदर्शन के बजाय एक गुणवत्ता के नजरिए से होता है। और नहीं, अपरिवर्तनीयता आपके ऐप में मौजूद संगामिति को माफ करने से आपको माफ नहीं करती है।


+1 यह समझ में आता है, लेकिन क्या आप इस बात का उदाहरण दे सकते हैं कि गहन रूप से अपरिवर्तनीय भाषा में आपको अभी भी संक्षिप्तता को ठीक से संभालने के बारे में चिंता कैसे करनी है? आप कहते हैं कि आप ऐसा करते हैं, लेकिन ऐसा दृश्य मेरे लिए स्पष्ट नहीं है
जिमी हॉफ

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

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

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

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

13

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

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

यह समझने के लिए कि यह कैसे काम करता है, मैं C # में कुछ सरल उदाहरण प्रस्तुत करने जा रहा हूं। इन उदाहरणों के सत्य होने के लिए, हमें कुछ धारणाएँ बनानी होंगी। पहला, यह कि संकलक त्रुटि के बिना C # विनिर्देश का अनुसरण करता है, और दूसरा, यह सही कार्यक्रमों का उत्पादन करता है।

मान लें कि मैं एक साधारण फ़ंक्शन चाहता हूं जो एक स्ट्रिंग संग्रह को स्वीकार करता है, और एक स्ट्रिंग देता है जो संग्रह में सभी स्ट्रिंग्स के कॉमास द्वारा अलग किए गए का एक संयोजन है। C # में एक सरल, भोलापन लागू हो सकता है:

public string ConcatenateWithCommas(ImmutableList<string> list)
{
    string result = string.Empty;
    bool isFirst = false;

    foreach (string s in list)
    {
        if (isFirst)
            result += s;
        else
            result += ", " + s;
    }
    return result;
} 

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

अब, मान लें कि मैं ऐसा करता हूं:

public string ConcatenateWithCommas(ImmutableList<string> list)
{
    var result = new StringBuilder();
    bool isFirst = false;

    foreach (string s in list)
    {
        if (isFirst)
            result.Append(s);
        else
            result.Append(", " + s);
    }
    return result.ToString();
} 

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

क्या यह फ़ंक्शन अपरिवर्तनीय है, भले ही StringBuilder परस्पर है?

हाँ यही है। क्यूं कर? क्योंकि हर बार इस फ़ंक्शन को कॉल किया जाता है, एक नया स्ट्रिंगबुलस्टल बनाया जाता है, बस उस कॉल के लिए। इसलिए अब हमारे पास एक शुद्ध कार्य है जो थ्रेड-सुरक्षित है, लेकिन इसमें परिवर्तनशील घटक हैं।

लेकिन अगर मैंने ऐसा किया तो क्या होगा?

public class Concatenate
{
    private StringBuilder result = new StringBuilder();
    bool isFirst = false;

    public string ConcatenateWithCommas(ImmutableList<string> list)
    {
        foreach (string s in list)
        {
            if (isFirst)
                result.Append(s);
            else
                result.Append(", " + s);
        }
        return result.ToString();
    } 
}

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

मैं ऐसा क्यों करना चाह सकता हूं? ठीक है, मैं चाहता हूं कि धागे resultआदेश के संबंध में मेरे बिना तार को जमा कर सकते हैं , या आदेश में जो धागे आते हैं। शायद यह एक लकड़हारा है, कौन जानता है?

वैसे भी, इसे ठीक करने के लिए, मैंने lockविधि के सराय के आसपास एक बयान दिया ।

public class Concatenate
{
    private StringBuilder result = new StringBuilder();
    bool isFirst = false;
    private static object locker = new object();

    public string AppendWithCommas(ImmutableList<string> list)
    {
        lock (locker)
        {
            foreach (string s in list)
            {
                if (isFirst)
                    result.Append(s);
                else
                    result.Append(", " + s);
            }
            return result.ToString();
        }
    } 
}

अब यह फिर से थ्रेड-सेफ है।

एकमात्र तरीका है कि मेरे अपरिवर्तनीय तरीके संभवतः थ्रेड-सुरक्षित होने में विफल हो सकते हैं यदि विधि किसी भी तरह इसके कार्यान्वयन का हिस्सा लीक करती है। क्या ऐसा हो सकता है? नहीं तो कंपाइलर सही है और प्रोग्राम सही है। क्या मुझे कभी ऐसे तरीकों पर ताले की आवश्यकता होगी? नहीं।

इस बात के उदाहरण के लिए कि क्रियान्वयन संभवत: संक्षिप्त परिदृश्य में कैसे लीक हो सकता है, यहां देखें


2
जब तक मैं गलत नहीं हूँ, क्योंकि एक Listउत्परिवर्तनीय है, पहले फ़ंक्शन में आपने 'शुद्ध' का दावा किया था, एक और धागा सूची से सभी तत्वों को हटा सकता है या फ़ॉरच लूप में होने पर अधिक गुच्छा जोड़ सकता है। निश्चित नहीं है कि यह एड IEnumeratorहोने के साथ कैसे खेलेगा while(iter.MoveNext()), लेकिन जब तक IEnumeratorअपरिवर्तनीय (संदिग्ध) नहीं होता है, तब तक फ़ॉरच लूप को फेंकने की धमकी दी जाएगी।
जिमी हॉफ़ा

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

मुझे नहीं लगता कि आप इसे 'शुद्ध' कह सकते हैं, जब इसमें वह परिवर्तनशील वस्तु है जिसे वह संदर्भ द्वारा उपयोग कर रहा है। यदि यह एक IEnumerable प्राप्त करता है, तो आप उस दावे को बनाने में सक्षम हो सकते हैं क्योंकि आप IEnumerable से तत्वों को जोड़ या हटा नहीं सकते हैं, लेकिन फिर यह IEnumerable के रूप में सौंपी गई एक सरणी या सूची हो सकती है, इसलिए IEnumerable अनुबंध किसी भी रूप की गारंटी नहीं देता है पवित्रता का। उस फ़ंक्शन को शुद्ध बनाने के लिए वास्तविक तकनीक पास-दर-कॉपी के साथ अपरिवर्तनीयता होगी, C # ऐसा नहीं करता है ताकि फ़ंक्शन को प्राप्त करने पर आपको सूची सही कॉपी करना पड़े; लेकिन ऐसा करने का एकमात्र तरीका उस पर एक प्रलोभन के साथ है ...
जिमी होफा

1
@ जिमीहॉफ्ता: दमित, आपने मुझे इस मुर्गी और अंडे की समस्या से रूबरू कराया! यदि आप कहीं भी समाधान देखते हैं, तो कृपया मुझे बताएं।
रॉबर्ट हार्वे

1
अभी यह उत्तर आया है और यह मेरे द्वारा आए विषय पर सबसे अच्छे स्पष्टीकरणों में से एक है, उदाहरण सुपर संक्षिप्त हैं और वास्तव में इसे आसान बनाना है। धन्यवाद!
स्टीफन बर्न ने

4

अगर मैं आपके सवालों को समझ गया तो मैं अनिश्चित हूँ।

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

भाग 2 का उत्तर - तालों को हमेशा बिना ताले के धीमा होना चाहिए।


3
भाग दो पूछ रहा है "ताले और अपरिवर्तनीय संरचनाओं के बीच प्रदर्शन व्यापार क्या है?" यह शायद अपने ही सवाल का हकदार है, अगर यह भी जवाबदेह है।
रॉबर्ट हार्वे

4

एक अपरिवर्तनीय वस्तु के लिए एक ही परस्पर संदर्भ में संबंधित राज्य के एक समूह को एनकैप्सुलेट करना, कई प्रकार के राज्य संशोधन के लिए पैटर्न का उपयोग करके लॉक-फ्री किया जा सकता है:

do
{
   oldState = someObject.State;
   newState = oldState.WithSomeChanges();
} while (Interlocked.CompareExchange(ref someObject.State, newState, oldState) != oldState;

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

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


4

आप से शुरू करते हैं

स्पष्ट रूप से अपरिवर्तनीयता मल्टी-प्रोसेसर प्रोग्रामिंग में ताले की आवश्यकता को कम करती है

गलत। आपको अपने द्वारा उपयोग किए जाने वाले प्रत्येक वर्ग के दस्तावेज़ को ध्यानपूर्वक पढ़ने की आवश्यकता है। उदाहरण के लिए, C ++ में const std :: string सुरक्षित नहीं है । अपरिवर्तनीय वस्तुओं में आंतरिक स्थिति हो सकती है जो उन्हें एक्सेस करते समय बदलती है।

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

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


2
const std::stringएक खराब उदाहरण और एक लाल हेरिंग का एक सा है। C ++ स्ट्रेंथ परिवर्तनशील हैं, और constवैसे भी अपरिवर्तनीयता की गारंटी नहीं दे सकते। सभी यह कहते हैं कि केवल constकार्यों को बुलाया जा सकता है। हालाँकि, वे फ़ंक्शंस अभी भी आंतरिक स्थिति को बदल सकते हैं, और constउन्हें दूर किया जा सकता है। अंत में, किसी भी अन्य भाषा के समान ही मुद्दा है: सिर्फ इसलिए कि मेरे संदर्भ का constमतलब यह नहीं है कि आपका संदर्भ भी है। नहीं, वास्तव में अपरिवर्तनीय डेटा संरचना का उपयोग किया जाना चाहिए।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.