2009-09-10 8 views
20

एक ऐसे मामले को देखते हुए जहां मेरे पास एक ऑब्जेक्ट है जो एक या एक से अधिक सच्चे/झूठे राज्यों में हो सकता है, मैं हमेशा थोड़ा अस्पष्ट रहा हूं कि प्रोग्रामर अक्सर कई बुलियन मूल्यों का उपयोग करने के बजाय झंडे + बिटमास्क का उपयोग क्यों करते हैं।बुलियन की श्रृंखला के बजाय झंडे + बिटमास्क का उपयोग क्यों करें?

यह सभी .NET ढांचे पर है। सुनिश्चित नहीं हैं कि अगर यह सबसे अच्छा उदाहरण है, लेकिन नेट ढांचा निम्नलिखित है:

public enum AnchorStyles 
{ 
    None = 0, 
    Top = 1, 
    Bottom = 2, 
    Left = 4, 
    Right = 8 
} 

तो एक लंगर शैली को देखते हुए, हम bitmasks का उपयोग जो राज्यों के चुने गए हैं यह पता लगाने कर सकते हैं। हालांकि, ऐसा लगता है कि आप एक ही चीज को एंकर स्टाइल क्लास/स्ट्रक्चर के साथ पूरा कर सकते हैं जिसमें प्रत्येक संभव मूल्य के लिए परिभाषित बूल गुण होते हैं, या व्यक्तिगत enum मानों की एक सरणी होती है।

बेशक मेरे प्रश्न का मुख्य कारण यह है कि मैं सोच रहा हूं कि मुझे अपने कोड के साथ एक समान अभ्यास का पालन करना चाहिए।

तो, इस दृष्टिकोण का उपयोग क्यों करें?

  • कम स्मृति खपत? (यह प्रतीत होता है जैसे यह एक सरणी/बूल की संरचना से कम उपभोग करेगा)
  • संरचना या सरणी से बेहतर स्टैक/ढेर प्रदर्शन?
  • तेजी से तुलना संचालन? तेज मूल्य वृद्धि/हटाने?
  • डेवलपर के लिए अधिक सुविधाजनक कौन लिखा है?
+2

ऐसा नहीं है कि मुझे एक मजबूत तर्क मिलता है, लेकिन यह ** ** कम स्मृति का उपभोग करता है। यह एक int (4 बाइट्स) का उपयोग करता है जबकि प्रत्येक बूल एक बाइट का उपयोग करता है। तो, 4 बूल एक int के समान उपयोग करता है। 32 बूल 32 बाइट्स का उपयोग करते हैं, जबकि वे सभी बूल एक ही enum में हो सकते हैं। और यदि आप अनुशंसित पथ पर नहीं जाते हैं, तो आप 8 बाइट लंबा बना सकते हैं (आकार (लंबा))। –

+0

इसे स्पष्ट करने के लिए धन्यवाद। इसने मुझे इस पोस्ट का नेतृत्व किया: http://stackoverflow.com/questions/294905/why-in-net-system-boolean-takes-4-byte –

+0

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

उत्तर

13

यह परंपरागत रूप से स्मृति उपयोग को कम करने का एक तरीका था। तो, हाँ, इसकी काफी अप्रचलित सी में # :-)

एक प्रोग्रामिंग तकनीक के रूप में, यह आज के सिस्टम में अप्रचलित हो सकता है, और आप काफी bools की एक सरणी का उपयोग करने के ठीक होगा, लेकिन ...

बिटमैस्क के रूप में संग्रहीत मानों की तुलना करना तेज़ है।AND और OR तर्क ऑपरेटर का उपयोग करें और परिणामी 2 इंट्स की तुलना करें।

यह काफी कम स्मृति का उपयोग करता है। बिटमैस्क में अपने सभी 4 उदाहरण मानों को डालकर आधे बाइट का उपयोग किया जाएगा। बूल की एक सरणी का उपयोग करके, संभवतः सरणी ऑब्जेक्ट के लिए कुछ बाइट्स और प्रत्येक बूल के लिए एक लंबा शब्द का उपयोग करना होगा। यदि आपको दस लाख मूल्यों को स्टोर करना है, तो आप देखेंगे कि बिटमैस्क संस्करण बेहतर क्यों है।

यह प्रबंधित करना आसान है, आपको केवल एक पूर्णांक मान से निपटना होगा, जबकि डेटाबेस का कहना है कि बूल की एक सरणी काफी भिन्न रूप से स्टोर करेगी।

और, मेमोरी लेआउट की वजह से, सरणी से हर पहलू में बहुत तेज है। यह लगभग 32-बिट पूर्णांक का उपयोग करने जितना तेज़ है। हम सभी जानते हैं कि डेटा पर संचालन के लिए जितना तेज़ हो सकता है।

1

यह गति और दक्षता के लिए है। अनिवार्य रूप से आप जिनके साथ काम कर रहे हैं वह एक ही int है।

if ((flags & AnchorStyles.Top) == AnchorStyles.Top) 
{ 
    //Do stuff 
} 
+0

यह एक बहुत उच्च स्तर का जवाब है। क्या आप इस बारे में विशिष्ट हो सकते हैं कि कौन से ऑपरेशन तेजी से/अधिक कुशल हैं और क्यों? या किसी ऐसे लेख से लिंक करें जो आपके दावे को न्यायसंगत ठहराता है? –

+0

क्या मुझे वास्तव में आपको सबूत देने की ज़रूरत है कि देशी प्रकारों और सरल तर्क अभिव्यक्तियों के साथ काम करना तेज़ और कुशल है? – ChaosPandion

+0

संचालन के आदेश को मत भूलना। आपको वहां बिटवाईयर ऑपरेशन के आसपास कोष्ठक रखना होगा। –

12
  • आसान किसी भी क्रम में कई झंडे की स्थापना।

  • सहेजने और डेटाबेस में 0101011 की सेरी प्राप्त करने में आसान है।

+2

ध्यान दें कि अलग-अलग कॉलम के रूप में, SQL सर्वर इन्हें एक बाइट में अनुकूलित करेगा: http://msdn.microsoft.com/en-us/library/ms177603.aspx – AaronLS

6

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

+0

ऐसा लगता है कि कक्षा में बूलियन मान जोड़ना है जितना आसान: बूल न्यूस्टेट; प्रतिलिपि बनाने के संबंध में, यह एक संरचना की प्रतिलिपि बनाना उतना आसान लगता है। –

+0

@ विंस्टन: सीरियलाइजेशन प्रारूप में परिवर्तन, और अच्छे धारावाहिक जो पुराने डेटा के लिए डिफ़ॉल्ट मान स्वीकार करते हैं, और जहां पुराने संस्करण अज्ञात फ़ील्ड को फेंक नहीं पाते हैं, उन्हें ढूंढना मुश्किल होता है। बाइनरी इंटरफ़ेस में परिवर्तन होता है, जो आवश्यक अपडेट की श्रृंखला का कारण बन सकता है, और संरचना के लिए पूर्ण सत्यापन समर्थन की आवश्यकता होती है। (निश्चित रूप से * अनुबंध * को स्पष्ट रूप से अवश्य कहना होगा "अज्ञात बिट्स को अनदेखा किया जाता है" या "अज्ञात बिट्स एक त्रुटि का कारण बनता है")। इसके अलावा, कार्यान्वयन स्तर पर, उन्हें पूरी तरह से संभालना आसान है। – peterchen

+1

@ विंस्टन क्या होगा यदि आपने एपीआई बनाया है? फिर आपके नए संस्करण में अपग्रेड करने वाले सभी को कोड बदलना होगा क्योंकि एक विधि में एक नया बूल जोड़ा गया था। यद्यपि यह एक enum था, तो वहां पर एक ही कोड रखने के लिए वहां पर कोई बदलाव नहीं किया जाना चाहिए। यही कारण है कि।नेट फ्रेमवर्क बुलियन पर enums के पक्ष में है। –

3

वास्तव में, यह बेहतर प्रदर्शन हो सकता है, मुख्य रूप से यदि आपका enum बाइट से निकला है। उस चरम मामले में, प्रत्येक enum मान को बाइट द्वारा दर्शाया जाएगा, जिसमें सभी संयोजन शामिल हैं, 256 तक। बुलियन के साथ इतने सारे संभावित संयोजन होने से 256 बाइट हो जाएंगे।

लेकिन फिर भी, मुझे नहीं लगता कि यह वास्तविक कारण है। कारण मैं उनको पसंद करता हूं वह शक्ति सी # मुझे उन enums को संभालने के लिए देता है। मैं एक अभिव्यक्ति के साथ कई मान जोड़ सकता हूं। मैं उन्हें भी हटा सकता हूं। मैं enum का उपयोग कर एक ही अभिव्यक्ति के साथ कई मूल्यों की तुलना भी कर सकता हूं। बुलियन के साथ, कोड बन सकता है, मान लें, अधिक verbose।

+3

256 संयोजन हैं, लेकिन केवल 8 झंडे हैं। उन्हें भ्रमित मत करो। – Dykam

+0

क्षमा करें, मेरी अंग्रेजी पर्याप्त स्पष्ट नहीं थी। आप सही हे। –

+1

बूल का उपयोग कर 256 संयोजन? यह 8 बूल मूल्य है। 8 बूल मान 256 बाइट नहीं हैं। – CoperNick

5

यह विधि स्पष्ट भी कर सकता है। 10 बूल बनाम 1 बिटमैस्क के साथ एक विधि की कल्पना करो।

2

मैं सुझाव दूंगा कि जब तक आप कुछ गंभीर गंभीर स्मृति सीमाओं (संभवतः नहीं) से निपट रहे हों, तब तक मैं कभी भी enum flags का उपयोग नहीं करूँगा। आपको हमेशा रखरखाव के लिए अनुकूलित कोड लिखना चाहिए।

कई बुलियन गुण होने से कोड को पढ़ने और समझना आसान हो जाता है, मूल्यों को बदलना पड़ता है, और इंटेलिसेंस टिप्पणियां प्रदान नहीं करती हैं जो बग की संभावना को कम करने के लिए नहीं देती हैं। यदि आवश्यक हो, तो आप हमेशा आंतरिक रूप से एक enum ध्वज फ़ील्ड का उपयोग कर सकते हैं, बस सुनिश्चित करें कि आप बूलियन गुणों के साथ मानों की सेटिंग/प्राप्त करने का पर्दाफाश करते हैं।

3

रेमंड चेन a blog post on this subject है।

ज़रूर, bitfields डेटा स्मृति बचाने के लिए, लेकिन आप कोड आकार, debuggability, और कम बहु सूत्रण में लागत के खिलाफ इसे संतुलित करने की है।

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

+2

रेमंड बिटटास्क के बारे में बात नहीं कर रहा है, बिटमैस्क नहीं। – gbjbaanb

1

एक डोमेन मॉडल परिप्रेक्ष्य से, यह कुछ स्थितियों में वास्तविकता मॉडल को बेहतर बनाता है। यदि आपके पास AccountIsInDefault और IsPreferredCustomer और RequiresSalesTaxState जैसे तीन बूलियन हैं, तो उन्हें एक ही ध्वज सजाए गए गणना में जोड़ने का अर्थ नहीं है, क्योंकि वे एक ही डोमेन मॉडल तत्व के लिए तीन अलग-अलग मान नहीं हैं।

लेकिन आप की तरह बूलियन्स का एक सेट है, तो:

[Flags] enum AccountStatus {AccountIsInDefault=1, 
     AccountOverdue=2 and AccountFrozen=4} 

या

[Flags] enum CargoState {ExceedsWeightLimit=1, 
     ContainsDangerousCargo=2, IsFlammableCargo=4, 
     ContainsRadioactive=8} 

तो यह खाता की कुल राज्य, (या कार्गो) स्टोर करने के लिए सक्षम होने के लिए उपयोगी है एक चर में ... जो एक डोमेन तत्व का प्रतिनिधित्व करता है जिसका मूल्य राज्यों के किसी भी संभावित संयोजन का प्रतिनिधित्व कर सकता है।

1
  1. अंतरिक्ष दक्षता - 1 बिट
  2. समय दक्षता - बिट तुलना जल्दी से हार्डवेयर द्वारा नियंत्रित किया जाता है।
  3. भाषा आजादी - जहां कई अलग-अलग कार्यक्रमों द्वारा डेटा को संभाला जा सकता है, आपको विभिन्न भाषाओं/प्लेटफार्मों में बूलियन के कार्यान्वयन के बारे में चिंता करने की आवश्यकता नहीं है।

अधिकांश समय, ये रखरखाव के मामले में ट्रेडऑफ के लायक नहीं हैं। पर, कई बार कर रहे हैं जब यह उपयोगी है:

  1. नेटवर्क प्रोटोकॉल - संदेशों
  2. विरासत सॉफ्टवेयर के आकार में कटौती करने में एक बड़ी बचत होगी - एक बार मैं कुछ विरासत सॉफ्टवेयर में पता लगाने के लिए कुछ जानकारी जोड़ने के लिए किया था।

शीर्षलेख को संशोधित करने की लागत: लाखों डॉलर और प्रयास के वर्षों। हेडर में 2 बाइट्स में जानकारी को shoehorn करने के लिए लागत का उपयोग नहीं किया जा रहा था: 0.

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

+1

1. अंतरिक्ष दक्षता केवल बहुत घने पैकिंग या बेहद सीमित वातावरण में लागू होती है; 2. समय दक्षता मुखौटा के कुशल उपयोग पर निर्भर करती है (और यह निश्चित रूप से * एक बुलियन मूल्य की तुलना करने के लिए एक बिट से मास्क-और-तुलना करने के लिए तेज़ नहीं है); 3. लागू नहीं है, एक बुलियन प्रकार का गलत इस्तेमाल करके एक बुलियन प्रकार का गलत इस्तेमाल कर रहा है। – user2864740