रासायनिक और रासायनिक इंजीनियरिंग
मल्टी-थ्रेडेड इंजीनियरिंग अनुप्रयोगों में सिंगलटन पैटर्न को लागू करते समय कॉमन मिस्टकेस से बचना
Table of Contents
परिचय: मल्टी-थ्रेडेड इंजीनियरिंग अनुप्रयोगों में सिंगलटन पैटर्न
सिंगलटन पैटर्न सॉफ्टवेयर इंजीनियरिंग में सबसे व्यापक रूप से इस्तेमाल किए जाने वाले रचनात्मक डिजाइन पैटर्न में से एक है। यह सुनिश्चित करता है कि एक वर्ग का केवल एक उदाहरण है और उस उदाहरण तक वैश्विक दृष्टिकोण प्रदान करता है। एकल-थ्रेडेड अनुप्रयोगों में, एक सिंगलटन को लागू करना सीधा है: निर्माता को निजी बनाना, एक स्थिर विधि प्रदान करना जो उत्सुक या आलसी रूप से उत्पन्न एक एकल उदाहरण देता है। हालांकि, बहु-थ्रेडेडेड इंजीनियरिंग अनुप्रयोगों में - जैसे एम्बेडेड सिस्टम, उच्च आवृत्ति वाले ट्रेडिंग प्लेटफॉर्म, वास्तविक समय नियंत्रण प्रणाली, और वितरित डेटाबेस - समस्या काफी जटिल हो जाती है। थ्रेड सुरक्षा, स्मृति दृश्यता और प्रदर्शन बाधाएं सावधानीपूर्वक डिजाइन की मांग करती हैं।
यह लेख बहु-थ्रेडेडेड वातावरण में सिंगलटन पैटर्न को लागू करते समय सबसे आम गलतियों डेवलपर्स की जांच करता है, अंतर्निहित कारणों को बताता है, और उनसे बचने के लिए सर्वोत्तम प्रथाओं और पैटर्न का एक व्यापक सेट प्रदान करता है। इसमें जावा में व्यावहारिक कोड उदाहरण भी शामिल हैं, जिसमें सी ++ और सी # में समकक्ष पैटर्न के संदर्भ हैं, और आगे पढ़ने के लिए बाहरी संसाधनों की सिफारिश करता है।
सिंगलटन कार्यान्वयन में आम गलतियां
यहां तक कि अनुभवी डेवलपर्स भी एक ही समय में एक ही समय में एक ही समय में एक ही समय में एक ही समय में एक ही समय में एक ही समय में एक ही समय में एक बार एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर एक बार फिर से शुरू हुआ।
1. कंस्ट्रक्टर प्राइवेट नहीं बनाना
किसी भी एकल टन की नींव एक निजी निर्माता है जो बाहरी तात्कालिकता को रोकता है। यदि निर्माता सुलभ है (सार्वजनिक, संरक्षित, या पैकेज-निजी), तो कोई भी धागा एक नया उदाहरण बना सकता है, एकल टन अनुबंध को तोड़ सकता है। बहु-धागा कोड में, यह अनजाने में तब हो सकता है जब एक वर्ग का पुनर्निर्माण हो और निर्माता दृश्यता को गलती से बदल दिया जाता है, या जब वर्ग को उपवर्गीकृत किया जाता है (हालांकि एक एकल टन को उपश्रेणी में आम तौर पर हतोत्साहित किया जाता है)। हमेशा निर्माता को निजी घोषित करते हैं, और यदि आपको उपवर्गों (दुर्धारण) का समर्थन करना चाहिए, तो अत्यधिक सावधानी के साथ एक संरक्षित निर्माता का उपयोग करें और अपेक्षित व्यवहार को दस्तावेज दें।
2. थ्रेड सुरक्षा को संभालने के लिए Failing
एक एकल-थ्रेडेड वातावरण में, एक सरल आलसी प्रारंभिककरण ठीक काम करता है:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
लेकिन एक बहु-थ्रेडेड एप्लिकेशन में, दो या अधिक धागे समवर्ती रूप से में प्रवेश कर सकते हैं, किसी भी धागे से पहले जांच करें, उदाहरण बना दिया है। प्रत्येक धागे के बाद अपने खुद के ऑब्जेक्ट बनाने के लिए आगे बढ़ें, पैटर्न का उल्लंघन करना। यह एक क्लासिक ]race शर्त] है, जिसके परिणामस्वरूप कई उदाहरण होते हैं और असंगत राज्य या संसाधन लीक हो सकते हैं।
3. उचित सिंक्रनाइज़ेशन के बिना आलसी प्रारंभिककरण का उपयोग करना
यहां तक कि डेवलपर्स जो थ्रेड सुरक्षा की आवश्यकता को पहचानते हैं, अक्सर सिंक्रनाइज़ेशन को नैली जोड़ते हैं। उदाहरण के लिए, पूरे [[FLT: 3]] विधि कार्यों को सिंक्रनाइज़ करना लेकिन एक प्रदर्शन की बोतल नेक पेश करना:
public static synchronized Singleton getInstance() { ... }
हर बार ] को कॉल करने और लॉक को जारी करने के बाद भी, उदाहरण पहले से ही बनाया गया है। उच्च-content परिदृश्यों में, यह ओवरहेड गंभीर रूप से थ्रूपुट को कम कर सकता है। बेहतर दृष्टिकोण डबल-चेकबंद लॉकिंग [ (नीचे गिराया गया), लेकिन यहां तक कि उस पैटर्न में अगर सही ढंग से लागू नहीं किया गया तो गिरना पड़ता है।
4. ओवरयूज्डिंग सिंक्रोनाइज़ेशन
सिंक्रनाइज़ेशन कई रूपों में आता है: विधियों, ब्लॉक, , , और आगे. ओवर-सिंक्रोनाइज़ेशन-अंकित मोटे-ग्रेन किए गए ताले को लागू करते समय ठीक-ग्रेन किए गए नियंत्रण उपलब्ध है- अनावश्यक संघननन की बात है। कुछ इंजीनियरिंग अनुप्रयोगों में (जैसे, सख्त विलंबता बजट के साथ वास्तविक समय की व्यवस्था), यहां तक कि लॉक ओवरहेड के कुछ सौ नैनोसेकेंड भी अस्वीकार्य हो सकते हैं। लक्ष्य महत्वपूर्ण अनुभाग को कम करना है जबकि अभी भी धागा सुरक्षा सुनिश्चित करना है।
5. ]volatile कीवर्ड की पहचान करना
जावा, सी # और सी ++ जैसी भाषाओं में (]), volatile] कीवर्ड (या समकक्ष) बहु-थ्रेडेडेड कोड में सही दृश्यता के लिए आवश्यक है। इसके बिना, कम्पाइलर या सीपीयू निर्देश को दोबारा व्यवस्थित कर सकता है, और एक धागे से बने बदलाव दूसरे के लिए दिखाई नहीं दे सकते हैं। डबल-चेकबंद लॉकिंग पैटर्न में, सिंगलटन उदाहरण को घोषित करने में विफल होने के कारण आंशिक रूप से निर्मित वस्तु को देखने के लिए एक धागा हो सकता है, जिससे अप्रत्याशित व्यवहार होता है। यह सबसे सूक्ष्म और खतरनाक गलतियों में से एक है।
थ्रेड-सेफ सिंगलटन कार्यान्वयन के लिए सर्वश्रेष्ठ अभ्यास
इन नुकसानों से बचने के लिए, इन सिद्ध रणनीतियों का पालन करें। प्रत्येक दृष्टिकोण थ्रेड सुरक्षा, प्रदर्शन और सादगी को संबोधित करता है।
निजी कन्स्ट्रक्टर और स्टेटिक इंस्टेंस
प्रारंभिक रणनीति के बावजूद, निर्माता निजी होना चाहिए। एकल उदाहरण को स्थिर क्षेत्र में संग्रहीत किया जाना चाहिए। किसी भी तरह से निर्माता को उजागर न करें, और उपश्रेणी को रोकने के लिए जावा (या [[FLT: 13]]]] में वर्ग [[FLT: 12]] बनाने पर विचार करें।
केवल तभी सिंक्रोनाइज़्ड ब्लॉक्स का उपयोग करें जब आवश्यक हो
आलसी प्रारंभिककरण के लिए, डबल-चेकबंद लॉकिंग पैटर्न सिंक्रनाइज़ेशन ओवरहेड को कम करता है:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
Singleton result = instance; // Local variable for performance
if (result == null) {
synchronized (Singleton.class) {
result = instance;
if (result == null) {
instance = result = new Singleton();
}
}
}
return result;
}
}
इस कोड में, सिंक्रनाइज़ ब्लॉक के बाहर ] लॉक ओवरहेड से बचाता है जब पहले से मौजूद है। आंतरिक जांच यह सुनिश्चित करती है कि केवल एक धागा उदाहरण बनाता है। कीवर्ड निर्देश को फिर से व्यवस्थित करने से रोकता है और यह सुनिश्चित करता है कि असाइनमेंट ] अन्य धागे के लिए पूरी तरह से दिखाई दे रहा है। ध्यान दें कि हम प्रदर्शन के लिए एक स्थानीय परिवर्तनीय में उदाहरण कैश करते हैं। यह पैटर्न जावा 5+ (समर्थित मेमोरी मॉडल के साथ) में सही है और इसी तरह C# और C++ में काम करता है (]] स्मृति आदेश के साथ)।
Eager intermination
यदि सिंगलटन की हमेशा आवश्यकता होती है और निर्माण सस्ता होता है, तो उत्सुक प्रारंभिककरण सरल धागा सुरक्षित दृष्टिकोण है:
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
कक्षा लोड करने के लिए स्वाभाविक रूप से JVM द्वारा सिंक्रनाइज़ किया जाता है, इसलिए कोई अतिरिक्त समन्वय की आवश्यकता नहीं है। हालांकि, यह कक्षा लोड समय पर उदाहरण बनाता है, जो संसाधन-संविदा प्रणालियों में अवांछनीय हो सकता है या जब सिंगलटन रनटाइम कॉन्फ़िगरेशन पर निर्भर करता है जो अभी तक उपलब्ध नहीं है।
स्थैतिक धारक पैटर्न (Initialization-on-demand)
यह पैटर्न स्पष्ट सिंक्रनाइज़ेशन के बिना थ्रेड सुरक्षा के साथ आलसी प्रारंभिककरण को जोड़ती है:
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
] वर्ग को केवल तभी लोड किया जाता है जब ] को पहली बार बुलाया जाता है, और JVM कक्षा लोडिंग के दौरान स्थैतिक क्षेत्र के सुरक्षित प्रकाशन की गारंटी देता है। इसे जावा सिंगलटन के लिए सबसे सुरुचिपूर्ण समाधान के रूप में व्यापक रूप से माना जाता है।
एनम-आधारित सिंगलटन (जावा)
जोशुआ ब्लोक का ]प्रभावी जावा एक enum का उपयोग करने की सिफारिश करता है:
public enum Singleton {
INSTANCE;
// methods and fields
}
एनम स्थिरांक को स्पष्ट रूप से ] कहा जाता है, और जावा भाषा गारंटी देता है कि एनम उदाहरण केवल एक बार बनाए जाते हैं, यहां तक कि सीरियलाइजेशन या प्रतिबिंब हमलों के तहत भी। यह दोनों धागा सुरक्षित और संक्षिप्त है। हालांकि, enums कक्षाओं को विस्तारित नहीं कर सकते हैं (केवल इंटरफ़ेस लागू करें), इसलिए वे सभी उपयोग मामलों के लिए उपयुक्त नहीं हैं।
C++ और C# में समतुल्य पैटर्न
C++ में, Meyer's Singleton (स्थानीय स्थैतिक प्रारंभिककरण) C++11 के बाद से धागा सुरक्षित है:
Singleton& getInstance() {
static Singleton instance;
return instance;
}
C# में, वर्ग एक अंतर्निहित धागा सुरक्षित आलसी प्रारंभिककरण प्रदान करता है:
public class Singleton {
private static readonly Lazy<Singleton> _lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => _lazy.Value;
}
इंजीनियरिंग अनुप्रयोगों में परीक्षण और विचार
इंजीनियरिंग अनुप्रयोगों में, सिंगलटन पैटर्न अक्सर हार्डवेयर ड्राइवरों, विन्यास सेटिंग्स, थ्रेड पूल या लॉगिंग सेवाओं जैसे साझा संसाधनों का प्रबंधन करता है। बहु-धागा परीक्षणों में ऐसे सिंगलटनों का परीक्षण करने के लिए सावधानीपूर्वक डिजाइन की आवश्यकता होती है। निम्नलिखित पर विचार करें:
- ]एकलटन परीक्षण करने योग्य उदाहरण को रीसेट करने का एक तरीका प्रदान करके (जैसे, एक संरक्षित विधि केवल परीक्षण में इस्तेमाल किया) या एक इंटरफ़ेस के माध्यम से निर्भरता को इंजेक्ट करके। कई आधुनिक अनुप्रयोग एकलटोन से बचने के लिए पूरी तरह से निर्भरता इंजेक्शन ढांचे के पक्ष में जो जीवन चक्र का प्रबंधन करते हैं।
- ]Performance profiling in real time or high-frequency system: मापने के ऊपर सिंक्रनाइज़ेशन. कुछ मामलों में, एक ताला मुक्त एकलton का उपयोग (C#) या (C++) को उचित ठहराया जा सकता है।
- Distributed system[ को एकल टन की आवश्यकता होती है, जो प्रक्रिया में नहीं, बल्कि प्रक्रिया में भी अद्वितीय होती है। यदि आपको क्लस्टर-वाइड सिंगलटन की आवश्यकता है, तो बाहरी समन्वय (जैसे, डेटाबेस, चिड़ियाघरकीपर या नेता चुनाव) का उपयोग करें।
- Reflection and serialization जावा सीरियलाइज़ेशन में ] का प्रयोग करें, और निर्माता में अपवाद फेंककर प्रतिबिंबित तत्कालीकरण को रोकने के लिए ] पहले से ही सेट है।
निष्कर्ष
सिंगलटन पैटर्न सॉफ्टवेयर इंजीनियर के टूलबॉक्स में एक मूल्यवान उपकरण बना हुआ है, लेकिन बहु-थ्रेडेडेड वातावरण में इसका कार्यान्वयन विस्तार से ध्यान देने की मांग करता है। सामान्य गलतियों को समझने और बचने के द्वारा- जैसे कि गैर-निजी निर्माता, लापता सिंक्रनाइज़ेशन, अनुचित अस्थिर उपयोग और ओवर-सिंच्रोनाइज़ेशन-विकास मजबूत, उच्च प्रदर्शन वाले सिंगलटन का उत्पादन कर सकते हैं। डबल-चेकबंद लॉकिंग पैटर्न, स्थिर धारक पैटर्न, और जावा में एनम-आधारित सिंगलटन प्रत्येक सुरक्षा और दक्षता का एक ठोस संतुलन प्रदान करते हैं। C++ और C# में, आधुनिक भाषा सुविधाओं ने आगे कार्य को सरल बनाया है।
आगे के अध्ययन के लिए, निम्नलिखित संसाधनों का उल्लेख करें:
- Wikipedia: Singleton पैटर्न
- ]Oracle जावा सिंगलटन ट्यूटोरियल
- ]"डबल चेक लॉकिंग टूटी हुई है" घोषणा
- ]माइक्रोसॉफ्ट.NET सिंगलटन पैटर्न]
अंततः, सबसे अच्छा सिंगलटन कार्यान्वयन वह है जो आपकी आवश्यकताओं के लिए सरल है। जब संदेह हो तो, उत्सुक प्रारंभिकता या स्थिर धारक पैटर्न को पसंद करते हैं, और हमेशा कंटेंटेशन के तहत सहीता को मान्य करने के लिए समवर्ती इकाई परीक्षण लिखते हैं।