2012-04-15 18 views
11

मैं map<MyStruct, I*> map1; का उपयोग कर रहा हूं। जाहिर है कि मेरे कुल ऐप समय का 9% वहां खर्च किया जाता है। विशेष रूप से मेरे प्रमुख कार्यों में से एक की एक पंक्ति पर। नक्शा बहुत बड़ा नहीं है (< 1k लगभग हमेशा, < 20 आम है)।stl मानचित्र प्रदर्शन?

क्या कोई वैकल्पिक कार्यान्वयन है जिसका उपयोग मैं करना चाहता हूं? मुझे लगता है कि मुझे अपना खुद नहीं लिखना चाहिए, लेकिन अगर मैंने सोचा कि यह एक अच्छा विचार था तो मैं कर सकता था।

अतिरिक्त जानकारी: मैं हमेशा तत्व जोड़ने से पहले जांचता हूं। यदि कोई कुंजी मौजूद है तो मुझे किसी समस्या की रिपोर्ट करने की आवश्यकता है। एक बिंदु के बाद से मैं लुकअप के लिए भारी नक्शा का उपयोग करूँगा और कोई और तत्व नहीं जोड़ूंगा।

+7

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

+1

क्या आप अपने तुलनात्मक फ़ंक्शन पर 'MyStruct' पर जानकारी साझा कर सकते हैं कि मानचित्र भी उपयोग करता है? – amit

+0

क्या आप बताए गए फ़ंक्शन के भीतर क्या कर रहे हैं इसके बारे में कुछ और जानकारी प्रदान कर सकते हैं? चूंकि मानचित्र की लुकअप जटिलता ओ (लॉग एन) है, मुझे यकीन नहीं है कि कोई सुधार कहाँ से आएगा। –

उत्तर

6

क्या यह insert करने के लिए जल्दी होगा और यह जांचें कि pair.secondfalse है यदि कुंजी पहले से मौजूद है?

इस

if (myMap.insert(make_pair(MyStruct, I*)).second == false) 
{ 
    //report error 
} 
else 
    // inserted new value 

तरह के बजाय हर बार एक find कॉल कर?

+0

उत्कृष्ट विचार। हालांकि memebers जोड़ने प्रदर्शन प्रदर्शन समस्या के साथ लाइन नहीं है।मैं इसे जोड़ता हूं और प्रदर्शन –

+0

पर एक नज़र डालता हूं यदि आप वास्तव में एक संघर्ष है या नहीं, तो आप खोज को स्थगित कर देते हैं, तो संभवतः आप लुकअप के शेडलोड को खत्म नहीं करते हैं, जब तक कि आप कुछ अजीब नहीं कर रहे हैं और अधिक डुप्लिकेट मान उत्पन्न कर रहे हैं अद्वितीय लोग मैंने जो 'डालने' विधि विस्तृत किया है, वह एक जोड़ी को 'पहले' के साथ नए मान या डुप्लिकेट मान के लिए एक पुनरावर्तक के रूप में लौटाता है, दूसरा 'सत्य' अर्थात् सफलता और 'झूठी' अर्थात् डुप्लिकेट प्रविष्टि वाला बुलियन है। – EdChum

+0

मुझे थोड़ा मूर्खतापूर्ण लगता है कि इस तरह से आवेषण नहीं कर रहा है। मैं एक भीड़ में होना चाहिए या सोचा था कि यह फेंक दिया कोड था। –

2

जिस तरह से आप मानचित्र का उपयोग कर रहे हैं, आप MyStruct इंस्टेंस के आधार पर लुकअप कर रहे हैं और आपके विशेष कार्यान्वयन के आधार पर, आवश्यक तुलना महंगा हो सकती है या नहीं भी हो सकती है।

+0

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

4

यह एक लंबा शॉट हो सकता है, लेकिन छोटे संग्रह के लिए, कभी-कभी सबसे महत्वपूर्ण कारक cache प्रदर्शन होता है।

std::map के बाद से लागू करता है एक लाल काला पेड़ है, जो [AFAIK] नहीं बहुत कैश-कुशल - शायद एक std::vector<pair<MyStruct,I*>> के रूप में नक्शे को लागू करने में एक अच्छा विचार हो सकता है, और वहाँ द्विआधारी खोज का उपयोग करें [बजाय नक्शे के लुक-अप] map की तुलना में कैश में फ़िट होने की अधिक संभावना है, क्योंकि कम से कम यह केवल कुशल होना चाहिए [तत्वों को सम्मिलित करना बंद करें], क्योंकि std::vectormap की तुलना में कैश में फिट होने की अधिक संभावना है।

यह कारक [सीपीयू-कैश] आमतौर पर उपेक्षित और बड़े ओ नोटेशन में निरंतर छिपा हुआ होता है, लेकिन बड़े संग्रह के लिए इसका मुख्य प्रभाव हो सकता है।

+0

मेरे पास शायद एक कक्षा है जो एक जोड़ी के बजाय आंतरिक रूप से दो वैक्टर का उपयोग करती है और इसे मानचित्र के समान दिखती है। –

+1

@ एसिडज़ॉम्बी 24: 'जोड़ी' केवल एक सुझाव है। दो वैक्टरों के बारे में: मैं मानता हूं, यह वास्तव में बेहतर होगा कि 'जोड़ी' के 'वेक्टर' [कम फ़ील्ड -> कम स्मृति उपयोग -> अधिक संभावना है कि पूरा नक्शा कैश में फिट होगा]। इसका जवाब केवल छोटे संग्रहों पर कैश के महत्वपूर्ण बल पर जोर देना है, और यह याद दिलाना आमतौर पर अधिक महत्वपूर्ण है, इसके लिए बड़े ओ नोटेशन, क्योंकि स्थिरांक को उपेक्षित नहीं किया जाना चाहिए। – amit

+1

मानचित्र से वेक्टर में स्विच करते समय हमने कुछ मामलों में हमारे कोड में बड़े सुधार देखा है। हमें संदेह है कि वेक्टर के साथ कैशिंग प्रदर्शन बहुत अधिक है। –

1

क्या कोई वैकल्पिक कार्यान्वयन है जिसका उपयोग मैं करना चाहता हूं? मुझे लगता है कि मुझे अपना खुद नहीं लिखना चाहिए, लेकिन अगर मैंने सोचा कि यह एक अच्छा विचार था तो मैं कर सकता था।

यदि आप अच्छी तरह से समस्या को समझते हैं, तो आपको विस्तार से बताया जाना चाहिए कि आपका कार्यान्वयन बेहतर होगा।

map उचित संरचना है? यदि ऐसा है, तो आपकी मानक लाइब्रेरी का कार्यान्वयन अच्छी गुणवत्ता (अच्छी तरह अनुकूलित) की संभावना होगी।

MyStruct तुलना सरल हो सकती है?

समस्या कहां है - आकार बदलना? देखो?

क्या आपने अपनी संरचनाओं के लिए कॉपी को कम और आवंटित किया है?

+0

समस्या: लुकअप। उचित संरचना: शायद। मुझे कुंजी द्वारा एक संरचना (जिसे अन्य संरचना के साथ तुलना करने की आवश्यकता है) और इसके साथ जुड़े इंटरफ़ेस ऑब्जेक्ट को खोजने की आवश्यकता है। मुझे नहीं लगता कि ऑर्डर एक समस्या है क्योंकि यह आम तौर पर छोटा है। कॉपी/असाइन करें: ठीक है, मैं एक पीआरटी कॉपी करके असाइन करता हूं। यह अपरिवर्तनीय है इसलिए मुझे इसे हटाने के बारे में चिंता करने की ज़रूरत नहीं है। –

+0

मैं जांच कर रहा था कि मेरे सीएमपी func में दोनों structs शून्य हैं। इसे हटाने से इसे और अधिक दिखाने के लिए पर्याप्त तेज़ बना दिया गया। समग्र उत्तर के लिए +1। –

5

map के बजाय आप unordered_map कोशिश कर सकते हैं जो तत्व खोजने के लिए पेड़ के बजाय हैश कुंजी का उपयोग करता है। This answerunordered_mapmap से अधिक पसंद करते समय कुछ संकेत देता है।

+3

छोटे संग्रहों के लिए, हैश-मैप्स * आमतौर पर * धीमे लाल लाल-पेड़ होते हैं, इसलिए मुझे उम्मीद है कि इस मामले में इसका उपयोग केवल नकारात्मक प्रभाव होगा। – amit

+0

@amit: यहां तक ​​कि 20 तत्वों के साथ एक छोटे से संग्रह के लिए, [यह सरल तुलना] (http://ideone.com/YupK4) - एक साधारण कुंजी प्रकार के प्रतिबंध के तहत - मुझे 'unordered_set' के लिए बेहतर प्रदर्शन देता है '। वास्तविक तुलना में 'मायस्ट्रक्चर' और इसके लिए हैश फ़ंक्शन शामिल होगा। –

+0

मैंने unordered_map को देखा। त्रुटि संदेश पढ़ने के बाद (इसकी बड़ी ...) मुझे एहसास है कि मुझे एक हैशिंग फ़ंक्शन को लागू करने की आवश्यकता है। मुझे नहीं पता कि यह कैसे करना है। मैं एक char * कैसे हैश? एक जो 1 से 20 इंच लंबा (या अधिक) –

35

सबसे पहले आपको यह समझने की आवश्यकता है कि नक्शा क्या है और आप कौन से संचालन का प्रतिनिधित्व कर रहे हैं। एक std::map एक संतुलित बाइनरी पेड़ है, लुकअप O(log N) संचालन लेगा, जिनमें से प्रत्येक कुंजी की तुलना में कुछ अतिरिक्त है जो आप ज्यादातर मामलों (सूचक प्रबंधन) में अनदेखा कर सकते हैं। सम्मिलन सम्मिलन के बिंदु का पता लगाने के लिए लगभग उसी समय लेता है, साथ ही नए नोड का आवंटन, पेड़ में वास्तविक सम्मिलन और पुनर्वितरण। जटिलता फिर से O(log N) है हालांकि छुपे हुए स्थिरांक अधिक हैं।

जब आप यह निर्धारित करने का प्रयास करते हैं कि प्रविष्टि से पहले मानचित्र में कोई कुंजी है, तो आप लुकअप की लागत ले रहे हैं और यदि यह सफल नहीं होता है, तो प्रविष्टि के बिंदु का पता लगाने के लिए एक ही लागत है। आप std::map::insert का उपयोग करके अतिरिक्त लागत से बच सकते हैं जो एक जोड़ी को एक पुनरावर्तक के साथ वापस लौटाता है और एक बूल आपको बताता है कि सम्मिलन वास्तव में हुआ था या तत्व पहले से ही वहां था।

सिवाय इसके, आप (MyStruct सिर्फ एक int या उनमें से हजार पकड़ सकता है) को समझने के लिए महंगा यह अपनी चाबी है, जो क्या सवाल शो से बाहर हो जाता है की तुलना करने की जरूरत है, जो कुछ आप में लेने की जरूरत है लेखा।

अंत में, यह मामला है कि एक map अपनी आवश्यकताओं के लिए सबसे कारगर डेटा संरचना नहीं है हो सकता है, और आप या तो एक std::unordered_map (हैश तालिका) के उपयोग पर विचार के लिए निरंतर समय सम्मिलन उम्मीद है कि (यदि हैश फंक्शन चाहते हो सकता है भयानक) या छोटे डेटा सेट के लिए भी एक सादा आदेशित सरणी (या std::vector) सेट करता है जिस पर आप तत्वों का पता लगाने के लिए बाइनरी खोज का उपयोग कर सकते हैं (इससे अधिक महंगे प्रविष्टियों की लागत पर आवंटन की संख्या कम हो जाएगी, लेकिन यदि आयोजित प्रकार छोटे होते हैं, यह इसके लायक हो सकता है)

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

+0

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

+2

वैकल्पिक रूप से एक अंधेरे डालने के लिए आप 'निचला_बाउंड' का उपयोग कर सकते हैं, कुंजी की जांच कर सकते हैं, और फिर संकेतित प्रविष्टि का उपयोग करें (यदि आप संभावित रूप से महंगा वस्तु निर्माण से बचना चाहते हैं)। –

+0

संरचना वास्तव में एक त्वरित रैपर टेम्पलेट है जिसे मैंने लिखा है जिसमें टी * है। बिंदु '<'और' == 'जैसे ओपी' * पीआरटी ओपी * अन्य 'करेंगे, इसलिए यह पीआरटी पते से तुलना नहीं करता है। कंटेनरों का उपयोग करते समय यह मेरी ज़िंदगी को बेहद आसान बनाता है। एक और अच्छा संकेत है। +1 @ केरेकस्क बी –

1

टिप्पणियों में कहा गया है कि उचित कोड के बिना, आपको देने के लिए बहुत ही सार्वभौमिक उत्तर हैं। हालांकि, अगर MyStruct वास्तव में बड़ी है तो स्टैक प्रतिलिपि महंगा हो सकती है।

template <typename T> struct deref_cmp { 
    bool operator()(std::shared_ptr<T> lhs, std::shared_ptr<T> rhs) const { 
    return *lhs < *rhs; 
    } 
}; 

std::map<std::shared_ptr<MyStruct>, I*, deref_cmp<MyStruct>> mymap; 

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

आप कहते हैं कि करने के लिए इस

template <typename T> struct NullDeleter { 
    void operator()(T const*) const {} 
}; 
// needle being a MyStruct 
mymap.find(std::shared_ptr<MyStruct>(&needle,NullDeleter())); 

जरूरत नहीं की तरह एक तत्व को देखने चाहेंगे, तो इस अनुकूलन करने के लिए और अधिक संभावित है।

+0

मायस्ट्रक्चर वास्तव में टी * है जहां टी टेम्पलेट है;)। जोहान गेरेल उत्तर –

+1

पर मेरी पहली टिप्पणी देखें ठीक है, उस स्थिति में आपको इस पुनर्निर्देशन से परेशान नहीं होना पड़ेगा। – bitmask

+0

हाँ। तो वैसे भी सुझाव के लिए +1 :) –

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