जावा और C # एरे बाउंड्स और पॉइंटर डेरेफेर की जाँच करके मेमोरी सुरक्षा प्रदान करते हैं।
दौड़ की परिस्थितियों और गतिरोध की संभावना को रोकने के लिए एक प्रोग्रामिंग भाषा में क्या तंत्र लागू किया जा सकता है?
जावा और C # एरे बाउंड्स और पॉइंटर डेरेफेर की जाँच करके मेमोरी सुरक्षा प्रदान करते हैं।
दौड़ की परिस्थितियों और गतिरोध की संभावना को रोकने के लिए एक प्रोग्रामिंग भाषा में क्या तंत्र लागू किया जा सकता है?
जवाबों:
दौड़ तब होती है जब आपके पास एक वस्तु का एक साथ उपनाम होता है और, कम से कम, एलियास में से एक उत्परिवर्तित होता है।
तो, दौड़ को रोकने के लिए, आपको इन स्थितियों में से एक या अधिक को असत्य बनाने की आवश्यकता है।
विभिन्न दृष्टिकोण विभिन्न पहलुओं से निपटते हैं। फंक्शनल प्रोग्रामिंग तनाव को कम करती है जो कि म्यूटेबिलिटी को दूर करती है। लॉकिंग / एटमिक्स एक साथ दूर करते हैं। Affine type aliasing को हटाते है (Rust mutable aliasing को हटाता है)। अभिनेता मॉडल आमतौर पर अलियासिंग को हटा देते हैं।
आप उन वस्तुओं को प्रतिबंधित कर सकते हैं जिन्हें अलियास किया जा सकता है ताकि यह सुनिश्चित करना आसान हो जाए कि उपरोक्त शर्तों से बचा जाए। यही वह जगह है जहाँ चैनल और / या संदेश पासिंग स्टाइल आते हैं। आप किसी अन्य चैनल या कतार के अंत में, जो कि रेस फ्री होने की व्यवस्था है, की मनमानी मेमोरी को अलियास नहीं कर सकते। आमतौर पर एक साथ परहेज करके अर्थात ताले या परमाणु से।
इन विभिन्न तंत्रों का नकारात्मक पक्ष यह है कि वे उन कार्यक्रमों को प्रतिबंधित करते हैं जिन्हें आप लिख सकते हैं। प्रतिबंध जितना अधिक कुंद होगा, कार्यक्रम कम होंगे। इसलिए न तो कोई एलियासिंग और न ही कोई म्यूटेबिलिटी काम करती है, और इसके बारे में तर्क करना आसान है, लेकिन बहुत सीमित हैं।
इसलिए जंग इतनी हलचल पैदा कर रही है। यह एक इंजीनियरिंग भाषा है (अकादमिक एक के विपरीत) जो एलियासिंग और म्यूटेबिलिटी का समर्थन करती है लेकिन कंपाइलर की जांच है कि वे एक साथ नहीं होते हैं। हालांकि आदर्श नहीं, यह अपने पूर्ववर्तियों की तुलना में कार्यक्रमों के एक बड़े वर्ग को सुरक्षित रूप से लिखने की अनुमति देता है।
जावा और C # एरे बाउंड्स और पॉइंटर डेरेफेर की जाँच करके मेमोरी सुरक्षा प्रदान करते हैं।
पहले यह सोचना महत्वपूर्ण है कि C # और Java ऐसा कैसे करते हैं। वे परिभाषित व्यवहार में C या C ++ में अपरिभाषित व्यवहार को परिवर्तित करके ऐसा करते हैं: प्रोग्राम को क्रैश करें । अशक्त डीरेपर्स और एरे इंडेक्स अपवादों को कभी भी सही C # या Java प्रोग्राम में नहीं पकड़ा जाना चाहिए ; उन्हें पहली जगह में नहीं होना चाहिए क्योंकि कार्यक्रम में यह बग नहीं होना चाहिए।
लेकिन मुझे लगता है कि आपके प्रश्न से आपका क्या मतलब है! हम आसानी से एक "गतिरोध सुरक्षित" रनटाइम लिख सकते हैं जो समय-समय पर यह देखने के लिए जांचता है कि क्या एन थ्रेड्स एक-दूसरे पर पारस्परिक रूप से प्रतीक्षा कर रहे हैं और यदि ऐसा होता है तो कार्यक्रम को समाप्त कर दें, लेकिन मुझे नहीं लगता कि यह आपको संतुष्ट करेगा।
दौड़ की परिस्थितियों और गतिरोध की संभावना को रोकने के लिए एक प्रोग्रामिंग भाषा में क्या तंत्र लागू किया जा सकता है?
आपके सवाल का सामना करने वाली अगली समस्या यह है कि गतिरोध के विपरीत "दौड़ की स्थिति" का पता लगाना मुश्किल है। याद रखें, थ्रेड सेफ्टी के बाद हम जो कर रहे हैं, वह दौड़ को खत्म नहीं कर रहा है । हम कार्यक्रम को सही बनाने के बाद क्या कर रहे हैं कोई फर्क नहीं पड़ता कि कौन रेस जीतता है ! दौड़ की स्थिति के साथ समस्या यह नहीं है कि दो धागे एक अपरिभाषित क्रम में चल रहे हैं और हम नहीं जानते कि कौन पहले खत्म होने जा रहा है। दौड़ की स्थिति के साथ समस्या यह है कि डेवलपर्स भूल जाते हैं कि थ्रेड्स परिष्करण के कुछ आदेश संभव हैं और उस संभावना के लिए खाते में विफल हो सकते हैं।
तो आपका सवाल मूल रूप से "एक प्रोग्राम भाषा को सुनिश्चित कर सकता है कि क्या मेरा प्रोग्राम सही है?" और उस प्रश्न का उत्तर व्यवहार में है, नहीं।
इस प्रकार अब तक मैंने केवल आपके प्रश्न की आलोचना की है। मुझे यहाँ गियर बदलने की कोशिश करें और अपने प्रश्न की भावना को संबोधित करें। क्या ऐसे विकल्प हैं जो भाषा डिज़ाइनर बना सकते हैं जो उस भयानक स्थिति को कम कर देंगे, जिसमें हम मल्टीथ्रेडिंग के साथ हैं?
स्थिति वास्तव में भयानक है! मल्टीथ्रेडेड कोड को सही करना, विशेष रूप से कमजोर मेमोरी मॉडल आर्किटेक्चर पर, बहुत, बहुत मुश्किल है। यह सोचने के लिए शिक्षाप्रद है कि यह क्यों मुश्किल है:
तो एक स्पष्ट तरीका है कि भाषा डिजाइनर चीजों को बेहतर बना सकते हैं। आधुनिक प्रोसेसर के प्रदर्शन की जीत को छोड़ दें । सभी प्रोग्राम बनाएं, यहां तक कि बहु-थ्रेड वाले, एक बहुत मजबूत मेमोरी मॉडल है। यह कई कार्यक्रमों को बहुस्तरीय बना देगा, कई बार धीमी गति से, जो सीधे पहले स्थान पर बहुस्तरीय कार्यक्रम होने के कारण के खिलाफ काम करता है: बेहतर प्रदर्शन के लिए।
यहां तक कि मेमोरी मॉडल को छोड़कर, मल्टीथ्रेडिंग कठिन होने के अन्य कारण हैं:
वह अंतिम बिंदु आगे की व्याख्या करता है। "रचना" से मेरा मतलब निम्नलिखित है:
मान लीजिए कि हम एक डबल दिए गए इंट की गणना करना चाहते हैं। हम अभिकलन का सही कार्यान्वयन लिखते हैं:
int F(double x) { correct implementation here }
मान लीजिए कि हम एक int दिए गए स्ट्रिंग की गणना करना चाहते हैं:
string G(int y) { correct implementation here }
अब अगर हम एक डबल दिए गए स्ट्रिंग की गणना करना चाहते हैं:
double d = whatever;
string r = G(F(d));
जी और एफ को अधिक जटिल समस्या के सही समाधान के रूप में बनाया जा सकता है।
लेकिन गतिरोध के कारण ताले में यह संपत्ति नहीं है। एक सही विधि M1 जो L1, L2, और L2, L1 के क्रम में ताले को लेने वाली एक सही विधि M2 है, दोनों को एक ही प्रोग्राम में एक गलत प्रोग्राम बनाए बिना उपयोग नहीं किया जा सकता है। ताले इसे बनाते हैं ताकि आप यह न कह सकें कि "प्रत्येक व्यक्तिगत पद्धति सही है, इसलिए पूरी बात सही है"।
तो, भाषा डिजाइनर के रूप में हम क्या कर सकते हैं?
सबसे पहले, वहाँ मत जाओ। एक कार्यक्रम में नियंत्रण के कई थ्रेड्स एक बुरा विचार है, और थ्रेड्स में मेमोरी साझा करना एक बुरा विचार है, इसलिए इसे पहले स्थान पर भाषा या रनटाइम में न डालें।
यह स्पष्ट रूप से एक गैर स्टार्टर है।
आइए अब हमारा ध्यान और अधिक मौलिक प्रश्न की ओर दें: हमारे पास पहले स्थान पर कई धागे क्यों हैं? दो मुख्य कारण हैं, और वे अक्सर एक ही चीज में उलझ जाते हैं, हालांकि वे बहुत अलग हैं। उन्हें जब्त कर लिया जाता है क्योंकि वे दोनों विलंबता के प्रबंधन के बारे में हैं।
बुरा विचार। इसके बजाय, coroutines के माध्यम से एकल थ्रेडेड अतुल्यकालिक का उपयोग करें। सी # यह खूबसूरती से करता है। जावा, इतनी अच्छी तरह से नहीं। लेकिन यह मुख्य तरीका है कि भाषा डिजाइनरों की वर्तमान फसल थ्रेडिंग समस्या को हल करने में मदद कर रही है। await
सी # में ऑपरेटर (एफ # अतुल्यकालिक workflows और अन्य पूर्व कला से प्रेरित) अधिक से अधिक भाषाओं में शामिल किया जा रहा है।
भाषा डिजाइनर ऐसी भाषा सुविधाएँ बनाकर मदद कर सकते हैं जो समानता के साथ अच्छी तरह से काम करती हैं। उदाहरण के लिए, LINQ को स्वाभाविक रूप से PLINQ में कैसे बढ़ाया जाता है, इसके बारे में सोचें। यदि आप एक समझदार व्यक्ति हैं और आप अपने टीपीएल संचालन को सीपीयू-बाउंड संचालन तक सीमित करते हैं जो अत्यधिक समानांतर हैं और मेमोरी साझा नहीं करते हैं, तो आप यहां बड़ी जीत प्राप्त कर सकते हैं।
इसके अलावा हम क्या कर सकते हैं?
C # आपको लॉक में प्रतीक्षा करने की अनुमति नहीं देता है, क्योंकि यह गतिरोध के लिए एक नुस्खा है। C # आपको मान प्रकार पर लॉक करने की अनुमति नहीं देता है क्योंकि यह हमेशा गलत काम करता है; आप बॉक्स पर ताला लगाते हैं, मूल्य नहीं। C # आपको चेतावनी देता है कि यदि आप एक अस्थिर को अलियास करते हैं, क्योंकि अन्य व्यक्ति अर्थ / अधिग्रहित नहीं करता है। बहुत अधिक तरीके हैं जो कंपाइलर सामान्य समस्याओं का पता लगा सकते हैं और उन्हें रोक सकते हैं।
सी # और जावा ने आपको किसी भी संदर्भ वस्तु को मॉनिटर के रूप में उपयोग करने की अनुमति देकर एक विशाल डिजाइन त्रुटि की। यह सभी प्रकार की बुरी प्रथाओं को प्रोत्साहित करता है जो गतिरोधों को ट्रैक करने के लिए कठिन बना देता है और उन्हें सांख्यिकीय रूप से रोकने के लिए कठिन होता है। और यह हर ऑब्जेक्ट हेडर में बाइट्स को बर्बाद करता है। मॉनिटर वर्ग से मॉनिटर प्राप्त करने के लिए मॉनिटर्स की आवश्यकता होनी चाहिए।
एसटीएम एक सुंदर विचार है, और मैंने हास्केल में खिलौना कार्यान्वयन के साथ खेला है; यह आपको लॉक-आधारित समाधानों की तुलना में बहुत अधिक सुरुचिपूर्ण ढंग से सही भागों से सही समाधान बनाने की अनुमति देता है। हालांकि, मुझे यह कहने के लिए विवरण के बारे में पर्याप्त नहीं पता है कि इसे बड़े पैमाने पर काम करने के लिए क्यों नहीं बनाया जा सकता है; अगली बार जब आप उसे देखते हैं, जो डफी से पूछें।
प्रक्रिया पर आधारित भाषाओं में बहुत सारे शोध हुए हैं और मैं उस स्थान को बहुत अच्छी तरह से नहीं समझता हूं; स्वयं इस पर कुछ पत्र पढ़ने का प्रयास करें और देखें कि क्या आपको कोई जानकारी मिलती है।
जब मैंने रोज़लिन पर Microsoft पर काम किया था तब मैंने Coverity पर काम किया था, और मैंने जो कुछ किया था, उसमें से एक विश्लेषणकर्ता को रोस्लिन का उपयोग करते हुए सामने का छोर मिला। Microsoft द्वारा प्रदान किए गए एक सटीक शाब्दिक, वाक्य-विन्यास और अर्थ विश्लेषण के द्वारा, हम तब लेखन डिटेक्टरों की कड़ी मेहनत पर ध्यान केंद्रित कर सकते थे, जिनमें आम बहुपरत समस्याएं पाई जाती थीं।
एक बुनियादी कारण है कि हमारे पास दौड़ और गतिरोध हैं और यह सब सामान है क्योंकि हम प्रोग्राम लिख रहे हैं जो कहते हैं कि क्या करना है , और यह पता चला है कि हम सभी अनिवार्य प्रोग्राम लिखने में बकवास कर रहे हैं; कंप्यूटर वह करता है जो आप उसे बताते हैं, और हम इसे गलत काम करने के लिए कहते हैं। कई आधुनिक प्रोग्रामिंग भाषाएं घोषणात्मक प्रोग्रामिंग के बारे में अधिक से अधिक हैं: कहते हैं कि आप क्या परिणाम चाहते हैं, और संकलक को उस परिणाम को प्राप्त करने के लिए कुशल, सुरक्षित, सही तरीका बताएं। फिर से, LINQ के बारे में सोचो; हम आपको कहना चाहते हैं from c in customers select c.FirstName
, जो एक आशय व्यक्त करता है । संकलक को यह पता लगाने दें कि कोड कैसे लिखना है।
मशीन लर्निंग एल्गोरिदम हाथ से कोड किए गए एल्गोरिदम की तुलना में कुछ कार्यों में बेहतर होते हैं, हालांकि निश्चित रूप से इसमें कई ट्रेडऑफ़ हैं जिनमें शुद्धता, ट्रेन के लिए समय, खराब प्रशिक्षण द्वारा शुरू की गई पूर्वाग्रह, और इसी तरह शामिल हैं। लेकिन यह संभावना है कि एक महान कई कार्य जिन्हें हम वर्तमान में "हाथ से" कोड करते हैं, जल्द ही मशीन-जनित समाधानों के लिए उत्तरदायी होंगे। यदि मनुष्य कोड नहीं लिख रहे हैं, तो वे बग नहीं लिख रहे हैं।
क्षमा करें कि वहाँ एक छोटा सा जुआ था; यह एक बहुत बड़ा और कठिन विषय है और पीएल समुदाय में इस समस्या के स्थान पर प्रगति के बाद 20 वर्षों में कोई स्पष्ट सहमति नहीं बन पाई है।