2011-09-12 35 views
12

बॉक्सिंग एक मान प्रकार को ऑब्जेक्ट प्रकार में परिवर्तित करता है। या जैसा कि एमएसडीएन इसे रखता है, मुक्केबाजी एक "प्रबंधित ढेर पर एक संदर्भ प्रकार वस्तु के अंदर संरचना को लपेटने का संचालन है।"सी # - क्या पूल बॉक्स करना संभव है?

लेकिन यदि आप आईएल कोड को देखकर उसमें ड्रिल करने का प्रयास करते हैं, तो आप केवल जादू शब्द "बॉक्स" देखते हैं। अपने आस्तीन एक public T Value संपत्ति के साथ Box<T> की तरह, है, और एक पूर्णांक मुक्केबाजी

अटकलें, मुझे लगता है क्रम में किसी प्रकार का है कि जेनरिक आधारित गुप्त वर्ग ऊपर दिखाई देगा:

int i = 5; 
Box<int> box = new Box<int>; 
box.Value = 5; 

पूर्णांक बॉक्स से निकालना होगा बहुत सस्ता हो: return box.Value;

दुर्भाग्य से, मेरा प्रदर्शन-भूखा सर्वर एप्लिकेशन मुक्केबाजी का एक उचित हिस्सा है, विशेष रूप से decimals। इससे भी बदतर, ये बक्से अल्पकालिक हैं, जो मुझे संदेह करता है कि मैं दो बार भुगतान करता हूं, एक बार बॉक्स को तेज करने के लिए और उसके बाद फिर से कचरे के लिए बॉक्स को इकट्ठा करने के बाद।

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

मेरे विशिष्ट प्रश्न:

  • वहाँ क्रम एक पूल से बक्से लेने के लिए उत्प्रेरण के बजाय उन्हें instanciating के लिए एक मौजूदा तंत्र है?
  • मुक्केबाजी के दौरान बनाए गए उदाहरण का प्रकार क्या है? क्या मुक्केबाजी प्रक्रिया को मैन्युअल रूप से नियंत्रित करना संभव है, फिर भी अभी भी अनबॉक्सिंग के साथ संगत हो सकता है?

कि आखिरी सवाल अजीब लगता है, मैं क्या मतलब है कि मैं अपने ही Box<T> या DecimalBox वर्ग, बॉक्स/Unbox मैन्युअल रूप से बनाते यह पूल, और कर सकता है। लेकिन मैं उस कोड में विभिन्न स्थानों को जाना और संशोधित नहीं करना चाहता हूं जो बॉक्स किए गए मान (उर्फ अनबॉक्स) का उपभोग करते हैं।

+0

तुम सिर्फ जेनरिक/कस्टम वस्तुओं आदि का उपयोग/द्वारा बॉक्सिंग के संचालन को कम करने के विचार किया है।? 'बॉक्स 'निर्देश जानबूझकर अपारदर्शी है, हालांकि आप इसे अपने' बॉक्स 'उपरोक्त वर्ग के माध्यम से नकल कर सकते हैं। – dlev

+10

"मेरा आवेदन मुक्केबाजी का एक उचित हिस्सा है"। एक अजीब खेल, एकमात्र जीतने वाला कदम खेलना नहीं है। –

+5

"इससे भी बदतर, ये बक्से अल्पकालिक हैं, जो मुझे संदेह करता है कि मैं दो बार भुगतान करता हूं, एक बार बॉक्स को तेज करने के लिए और उसके बाद फिर से कचरे के लिए बॉक्स को इकट्ठा करने के बाद।" तुमने प्रोफाइल किया, है ना? यानी आप जानते हैं कि जीसी आपके आवेदन में एक बाधा है क्योंकि आपने अनुमान लगाया है, और इसलिए नहीं कि आपने अनुमान लगाया है। जीसी बाध्य होने में एकमात्र बार मैं बड़े बाइट एरे आवंटित कर रहा था। यदि Gen0 संग्रह एक बाधा है तो आपको अपने डिजाइन पर पुनर्विचार करना चाहिए। – CodesInChaos

उत्तर

10

अटकलें, मुझे लगता है क्रम जेनरिक आधारित गुप्त वर्ग तक अपनी आस्तीन

आपका अटकलों के कुछ प्रकार है लगभग सही है कि। तार्किक रूप से आप एक बॉक्स के बारे में सोच सकते हैं जो जादुई Box<T> प्रकार जैसा व्यवहार करता है जैसा व्यवहार करता है (जादू के कुछ और बिट्स के साथ; उदाहरण के लिए, जिस तरह से शून्य मूल्य प्रकार बॉक्स कम असामान्य है।) वास्तविक कार्यान्वयन विस्तार के रूप में , रनटाइम सामान्य प्रकार के साथ ऐसा नहीं करता है। बॉक्सिंग सीएलआर v1 में मौजूद थी, जो सामान्य प्रकार के प्रकार सिस्टम में जोड़े जाने से पहले था।

मेरा प्रदर्शन-भूखा सर्वर एप्लिकेशन मुक्केबाजी का एक उचित हिस्सा है, विशेष रूप से decimals।

यदि यह दर्द होता है जब आप उस कर कि तब बंद करो। मुक्केबाजी को सस्ता बनाने की कोशिश करने के बजाय, इसे पहले स्थान पर करना बंद करें। आप मुक्केबाजी क्यों दशमलव हैं?

इससे भी बदतर, इन बक्सों अल्पकालिक हैं, जो बनाता है मुझे संदेह है मैं बॉक्स का संग्रह करने के बाद उस पूरा कर लेने कचरा के लिए एक बार बॉक्स instanciating लिए दो बार भुगतान, और तब पुन।

शॉर्ट-लाइफ बेहतर लंबे समय से रहने से अधिक रहता है; अल्पकालिक ढेर वस्तुओं के साथ आप उन्हें इकट्ठा करने के लिए भुगतान करते हैं और फिर वे मर चुके हैं। लंबी अवधि के हीप ऑब्जेक्ट्स के साथ आप उस लागत को बार-बार भुगतान करते हैं क्योंकि ऑब्जेक्ट जीवित रहता है।

बेशक, आप शायद अल्पकालिक वस्तुओं के बारे में चिंतित होने वाली लागत प्रति संग्रह संग्रह की लागत नहीं है। इसके बजाय, यह संग्रह दबाव है; आवंटित अधिक अल्पकालिक वस्तुओं को लगातार कचरा संग्रह के बराबर बराबर होता है।

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

अगर मैं स्वयं इस स्मृति को पूरी तरह से कर रहा था, तो मैं यहां एक ऑब्जेक्ट पूल का उपयोग करने पर विचार करता हूं।

दाएं; आप लंबे समय तक जीवित वस्तु को इकट्ठा करने की लागत का भुगतान करते हैं, लेकिन आप कुल संग्रह कम करते हैं क्योंकि कम संग्रहण दबाव उत्पन्न होता है। यह एक जीत हो सकती है।

क्या रनटाइम को पूल से बक्से लेने के बजाय उन्हें निकालने के बजाय मौजूदा तंत्र है?

नहीं।

मुक्केबाजी के दौरान बनाए गए उदाहरण का प्रकार क्या है? क्या मुक्केबाजी प्रक्रिया को मैन्युअल रूप से नियंत्रित करना संभव है, फिर भी अभी भी अनबॉक्सिंग के साथ संगत हो सकता है?

बॉक्स का प्रकार बॉक्सिंग के प्रकार का प्रकार है। GetType को कॉल करके बस पूछें; यह आपको बताएगा। बक्से जादुई हैं; वे उस चीज़ का प्रकार हैं जिसमें वे शामिल हैं।

जैसा कि मैंने मुक्केबाजी को सस्ता बनाने की कोशिश करने के बजाए पहले कहा था, बस इसे पहले स्थान पर न करें।

+0

ऐसी स्थितियां हैं जहां मुक्केबाजी से बचना बहुत मुश्किल है। उन परिस्थितियों में से एक यह है कि जब आप स्थिर संपत्ति पंजीकरण और GetValue/SetValue प्रकार के उपयोग के साथ एक इकाई ढांचे का निर्माण कर रहे हैं, यानी WPF निर्भरता वस्तुओं/गुणों की तरह सोचें। हम अंततः मुक्केबाजी से बचने के लिए कुछ 'प्रतिबिंब। प्रवेश' वूडू जादू को चाबुक करेंगे लेकिन यह इस बिंदु पर एक बड़ा उपक्रम है ... बॉक्स कैश के लिए नीचे जवाब देखें, हमने इस दौरान हमारे मुद्दों को हल किया :) –

2

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

आप कैश को लागू करके पुनर्विक्रय करने वाले मानों के लिए मुक्केबाजी से बच सकते हैं। या आपको अपना खुद का बॉक्स प्रकार लागू करने की आवश्यकता है।

हालांकि आपका स्वयं का बॉक्स प्रकार object से मानक कलाकार के साथ अनबॉक्स नहीं किया जा सकता है। तो आपको उपभोग करने वाले कोड को अनुकूलित करने की आवश्यकता होगी।


अपनी खुद की विधि है कि एक बॉक्स्ड मान देता है लेखन: इस सरल कार्यान्वयन के साथ

[ThreadStatic] 
private static Dictionary<T,object> cache; 

public object BoxIt<T>(T value) 
    where T:struct 
{ 
    if(cache==null) 
    cache=new Dictionary<T,object>(); 
    object result; 
    if(!cache.TryGetValue(T,result)) 
    { 
    result=(object)T; 
    cache[value]=result; 
    } 
    return result; 
} 

एक समस्या यह है कि कैश आइटम कभी नहीं दूर करता है। अर्थात। यह एक स्मृति रिसाव है।

+0

इस कैश को कोई मदद कैसे है? यह अभी भी वही वस्तुएं बनाता है, उन्हें कभी भी खराब नहीं करता है। – configurator

+0

यदि आप समान मानों का उपयोग अक्सर करते हैं तो यह ऑब्जेक्ट नहीं बनाता है। लेकिन यदि अधिकांश मूल्य अद्वितीय हैं तो यह बुरा होगा। चूंकि मुझे नहीं पता कि ओपी क्या कर रहा है, मुझे नहीं पता कि कैश उपयोगी होगा या नहीं। जब बॉक्सिंग छोटे पूर्णांक (-128 से 127 अगर मुझे सही याद आती है) जावा जावा आंतरिक रूप से समान पैटर्न का उपयोग करता है। – CodesInChaos

0
int i = 5; 
object boxedInt = i; 

एक System.Object को एक मान प्रकार नियत अधिक या सभी कम वहाँ जहाँ तक अपने कोड का संबंध है मुक्केबाजी (मैं मुक्केबाजी आपरेशन तकनीकी जानकारी में नहीं मिलेगा) करने के लिए है।

System.Object चर में अपने दशमलव मान रखते हुए मुक्केबाजी से समय का एक सा बंद दाढ़ी कर सकते हैं और System.Object उदाहरणों बनाने, लेकिन आप हमेशा Unbox किया है। यदि आपको प्रत्येक मूल्य एक असाइनमेंट है, और इसलिए कम से कम एक मुक्केबाजी है, तो आपको यह मूल्य असंभव हो जाता है।

इस अभ्यास का एक उदाहरण है, हालांकि - नेट ढांचे आंतरिक रूप से पूर्व बॉक्स्ड बूलियन मूल्यों का उपयोग करता है एक वर्ग इस के समान में:

class BoolBox 
{ 
    // boxing here 
    private static object _true = true; 
    // boxing here 
    private static object _false = false; 

    public static object True { get { return _true; } } 
    public static object False { get { return _false; } } 
} 

WPF प्रणाली अक्सर निर्भरता गुणों के लिए System.Object चर का उपयोग करता है बस ऐसे मामले का नाम देने के लिए जहां इन 'आधुनिक समय' में मुक्केबाजी/अनबॉक्सिंग भी अपरिहार्य है।

4

रनटाइम आपके द्वारा वर्णित बहुत कुछ करता है, हालांकि जेनेरिक शामिल नहीं है, क्योंकि जेनेरिक मूल रूपरेखा का हिस्सा नहीं था।

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

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

+0

आपका उत्तर बहुत सही है, लेकिन पूलिंग रणनीति कई मामलों में समझ में आता है। हां, आप अधिक दीर्घकालिक वस्तुओं के साथ समाप्त होते हैं, जो महंगी हैं क्योंकि वे कई संग्रहों से बचते हैं। लेकिन अगर सबकुछ पूल किया जाता है, तो शायद ही कोई संग्रह होता है क्योंकि कुछ भी संग्रह दबाव नहीं बना रहा है। पूलिंग का विचार संग्रह की प्रति ऑब्जेक्ट लागत को कम नहीं करना है; बल्कि, विचार संग्रह की कुल संख्या को कम करना है। –

+0

हां, पूलिंग कुछ स्थितियों में मदद कर सकती है, लेकिन दशमलव मूल्यों को पूल करने से पहले से ही मौजूदा मानों के लिए कई हिट पैदा होने की संभावना नहीं है। यदि वही मानों का उपयोग किया जाएगा, तो परिणाम कैशिंग इनपुट पैरामीटर को कैशिंग करने से कहीं अधिक कुशल होगा। – Guffa

+0

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

0

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

मैं Dictionary में प्रत्येक मान को संग्रहीत करने के बारे में भी स्पष्ट करता हूं - आपकी स्मृति समस्या खराब हो जाएगी। यहां एक मुक्केबाजी ढांचा है जो उपयोगी हो सकता है।

public class Box 
{ 
    internal Box() 
    { } 

    public static Box<T> ItUp<T>(T value) 
     where T : struct 
    { 
     return value; 
    } 

    public static T ItOut<T>(object value) 
     where T : struct 
    { 
     var tbox = value as Box<T>; 
     if (!object.ReferenceEquals(tbox, null)) 
      return tbox.Value; 
     else 
      return (T)value; 
    } 
} 

public sealed class Box<T> : Box 
    where T : struct 
{ 
    public static IEqualityComparer<T> EqualityComparer { get; set; } 
    private static readonly ConcurrentStack<Box<T>> _cache = new ConcurrentStack<Box<T>>(); 
    public T Value 
    { 
     get; 
     private set; 
    } 

    static Box() 
    { 
     EqualityComparer = EqualityComparer<T>.Default; 
    } 

    private Box() 
    { 

    } 

    ~Box() 
    { 
     if (_cache.Count < 4096) // Note this will be approximate. 
     { 
      GC.ReRegisterForFinalize(this); 
      _cache.Push(this); 
     } 
    } 

    public static implicit operator Box<T>(T value) 
    { 
     Box<T> box; 
     if (!_cache.TryPop(out box)) 
      box = new Box<T>(); 
     box.Value = value; 
     return box; 
    } 

    public static implicit operator T(Box<T> value) 
    { 
     return ((Box<T>)value).Value; 
    } 

    public override bool Equals(object obj) 
    { 
     var box = obj as Box<T>; 
     if (!object.ReferenceEquals(box, null)) 
      return EqualityComparer.Equals(box.Value, Value); 
     else if (obj is T) 
      return EqualityComparer.Equals((T)obj, Value); 
     else 
      return false; 
    } 

    public override int GetHashCode() 
    { 
     return Value.GetHashCode(); 
    } 

    public override string ToString() 
    { 
     return Value.ToString(); 
    } 
} 

// Sample usage: 
var boxed = Box.ItUp(100); 
LegacyCode(boxingIsFun); 
void LegacyCode(object boxingIsFun) 
{ 
    var value = Box.ItOut<int>(boxingIsFun); 
} 

सब ईमानदारी में आप एक और सवाल करना चाहिए - और कैसे इस मुक्केबाजी मुद्दा आप से छुटकारा पाने के बारे में सलाह के लिए पूछना।

0

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

http://www.singulink.com/CodeIndex/post/value-type-box-cache

इसका उपयोग करने के बाद हमारी स्मृति उपयोग पागल की तरह गिरा दी गई। डेटाबेस में अनिवार्य रूप से सबकुछ ऑब्जेक्ट [] सरणी में संग्रहीत होता है और कई जीबी डेटा हो सकता है, इसलिए यह बेहद फायदेमंद था।मूल्य के लिए एक बॉक्स हो जाता है अगर एक आप के लिए अन्यथा यह यह बॉक्स कैश किया गया है -

  • object BoxCache<T>.GetBox(T value):

    वहाँ तीन मुख्य विधि का उपयोग करना चाहते हैं कर रहे हैं।

  • object BoxCache<T>.GetOrAddBox(T value) - मूल्य के लिए एक बॉक्स प्राप्त करता है यदि कोई कैश किया गया है अन्यथा यह कैश में एक जोड़ता है और इसे वापस करता है।
  • void AddValues<T>(IEnumerable<T> values) - कैश में निर्दिष्ट मानों के लिए बॉक्स जोड़ता है।
संबंधित मुद्दे