2016-02-05 4 views
8

मेरे पास एक विधि है जो पेड़ को पार करने और वस्तुओं को अपडेट करने के लिए रिकर्सन का उपयोग करती है।मेरा शब्दकोश सी # में समग्र कुंजी के साथ खराब प्रदर्शन क्यों कर रहा है?

वर्तमान में विधि सभी वस्तुओं को संसाधित करने में काफी समय लगता है, इसलिए मैंने चीजों को अनुकूलित करना शुरू कर दिया। उन चीजों में से प्रत्येक आइटम के लिए डीबी क्वेरी निष्पादित करने के बजाय एक शब्दकोश का उपयोग होता है। विधि चलाता है जब यह सभी आइटम अद्यतन करने के लिए चारों ओर 5000 recursions लेता

शब्दकोश के रूप में

System.Collections.Generic.Dictionary<EffectivePermissionKey, MyData> 

परिभाषित किया गया है कुंजी प्रकार

private struct EffectivePermissionKey 
{ 
    // http://blog.martindoms.com/2011/01/03/c-tip-override-equals-on-value-types-for-better-performance/ 
    public override bool Equals(object aObject) 
    { 
    if (aObject == null) 
     return false; 
    else 
     return aObject is EffectivePermissionKey && Equals((EffectivePermissionKey)aObject); 
    } 

    public bool Equals(EffectivePermissionKey aObject) 
    { 
    return this.ID == aObject.ID && this.OrchardUserID == aObject.OrchardUserID; 
    } 

    public override int GetHashCode() 
    { 
    // http://stackoverflow.com/a/32502294/3936440 
    return unchecked(ID.GetHashCode() * 23 * 23 + OrchardUserID.GetHashCode() * 23); 
    } 

    public int ID; 
    public int OrchardUserID; 
} 

के रूप में परिभाषित किया गया है।

प्रारंभ में यह 100 सेकंड शब्दकोश के बिना लिया गया।

int कुंजी के साथ एक शब्दकोश के उपयोग के द्वारा बदल दिया डीबी प्रश्नों के साथ एक पहले दृष्टिकोण 22 सेकंड ले लिया। WAT -

अब, डीबी प्रश्नों के साथ शब्दकोश ऊपर परिभाषित के उपयोग के द्वारा बदल दिया और उचित TryGetValue() लेता 97 सेकंड < कहता है।

यहां क्या हो रहा है? इस बड़े पैमाने पर प्रदर्शन ड्रॉप क्या हो सकता है?

संपादित

सबसे पहले, यह मेरे लिए एक हैश टक्कर मुद्दा तरह लग रहा था, तो मैं सत्यापित करने के लिए है कि इस विधि कहा जाता है, लेकिन यह नहीं कहा गया है, इसलिए कोई हैश टक्कर मैं अनुमान EffectivePermissionKey.Equals() में एक ब्रेकपाइंट जोड़ा।

EDIT2

अब मैं उलझन में हूँ। मैंने सोचा कि Equals() केवल तब कॉल हो जाता है जब हैश कोड मैच नहीं है। मेरी चाबियों के हैश कोड और TryGetValue() में उपयोग की जाने वाली कुंजियों को प्रिंट करने के बाद, मुझे लगता है कि ये कोड मेल खाते हैं। तो फिर मैं Dictionary<> के स्रोत कोड को देखा और वहां FindEntry() में एक पंक्ति है कि इस तरह दिखाई देता है:

if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i; 

इसका मतलब यह है शब्दकोश में प्रत्येक आइटम के लिए कुंजी GetHashCode()औरEquals() कहा जाता हो जाता है कि क्योंकि मैं सभी वस्तुओं की प्रक्रिया शब्दकोश में, क्योंकि आइटम डीबी क्वेरी का परिणाम हैं, जबकि इन परिणामों को जहां भी शब्दकोश दृष्टिकोण से पहले संसाधित किया जाता है।

+1

मुझे आपके 'बराबर' और 'गेटहाशकोड' के साथ कोई समस्या नहीं दिखाई दे रही है (मैं यहां प्रस्तुत 17/23 "संचयी" पसंद करता हूं http://stackoverflow.com/questions/263400/what-is-the- सर्वोत्तम-एल्गोरिदम-एक-ओवर-ऑर्डर-सिस्टम-ऑब्जेक्ट-गेटहाशकोड, लेकिन फिर भी आपके "गैर संचयी" संस्करण को बहुत से टकराव नहीं हो सकते हैं – xanatos

+5

शायद यह मुक्केबाजी/अनबॉक्सिंग के कारण है? 'प्रभावी पैरामिशनकी' 'IEquatable इसका मतलब है कि शब्दकोश 'ऑब्जेक्ट एक्वालिटी कॉम्पारेयर' –

+1

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

उत्तर

3

लोगों को कभी न मानें, अपना समय लेने के लिए खेद है, मेरा दृष्टिकोण पूरी तरह से गलत था। मुझे बताएं क्यों।

A -> recursion 1, DB query for permission of node A with ID = 1 
    B -> recursion 2, DB query for permission of node B with ID = 2 
    C -> recursion 3, DB query for permission of node C with ID = 3 
    D -> recursion 4, DB query for permission of node D with ID = 4 

आप देख सकते हैं, एक पेड़ प्रति नोड डीबी क्वेरी:

मुद्दा सादगी के लिए टूट

अब इस अनुकूलन के लिए त्रुटिपूर्ण दृष्टिकोण:

Dictionary<int, PermissionData> myMap 

... 

DB query of all permissions and insert into myMap 

... 

A -> recursion 1, myMap.TryGetValue(1, out ...) 
    B -> recursion 2, myMap.TryGetValue(2, out ...) 
    C -> recursion 3, myMap.TryGetValue(3, out ...) 
    D -> recursion 4, myMap.TryGetValue(4, out ...) 

अब आप देख सकते हैं कि क्वेरी एक बार, लेकिन प्रत्येक नोड एक TryGetValue() कॉल किया जाता है पर किया जाता है।

मेरी विशिष्ट मामले में यह वास्तव में धीमी है एकल प्रश्नों क्योंकि

  • शब्दकोश के रूप में ज्यादा के रूप में कुंजियां मौजूद नोड्स मौजूद हैं, क्योंकि प्रत्येक नोड एक डीबी अनुमति प्रविष्टि है क्रियान्वित करने के रूप में

और

  • प्रत्येक TryGetValue()

    में आवश्यक/परिणाम
    1. कुंजी उदाहरण
    2. Equals()

इन 4 कदम बुलाने की हैश की गणना TryGetValue()

  • बुला (आईडी और उपयोगकर्ता ID के साथ) एक प्रमुख उदाहरण बनाकर चारों ओर क्रियान्वित कर रहे हैं 5000 सरल इकाई ढांचे के प्रश्नों को निष्पादित करने के विरुद्ध 5000 बार (SELECT * FROM table WHERE ID = ...)। मुझे नहीं पता क्यों, लेकिन प्रश्न यहां तेजी से हैं, शायद संकलक कुछ दूर अनुकूलित करता है।

    वैसे भी, मैंने पूरी चीज को फिर से काम किया और अब मेरे पास उपयोगकर्ता आईडी पर बाहरी लूप है और एक आंतरिक रिकर्सिव ट्रैवर्सल चुड़ैल एक सरल int कुंजी (नोड आईडी) के साथ शब्दकोश का उपयोग करता है। यह मुझे तेजी से परिणाम प्रकाश देता है। पूरे निष्पादन में अब लगभग 16 सेकंड लगते हैं और कुछ और tweaks और थ्रेडिंग के साथ मैं इसे 1 सेकंड के नीचे नीचे मिला। मिशन पूरा हुआ।

  • +2

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

    संबंधित मुद्दे