2009-11-01 15 views
7

मेरे पास समानांतर है। फॉरएच लूप शरीर के अंदर एक गहन ऑपरेशन चला रहा है।समानांतर के अंदर हैशटेबल का उपयोग करना। फॉरएच?

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

हालांकि, क्योंकि मैं समानांतर का उपयोग कर रहा हूं। इसके लिए एक असुरक्षित समस्या है, जिसके कारण हैशटेबल है। जोड़ें और इसमें शामिल हैं (कुंजी) कॉल सिंक से बाहर हो जाती हैं, क्योंकि वे समानांतर में चल रहे हैं। ताले पेश करने से perf मुद्दों का कारण बन सकता है।

यहाँ नमूना कोड:

Hashtable myTable = new Hashtable; 
Parallel.ForEach(items, (item, loopState) => 
{ 
    // If exists in myTable use it, else add to hashtable 
    if(myTable.ContainsKey(item.Key)) 
    { 
     myObj = myTable[item.Key]; 
    } 
    else 
    { 
     myObj = SomeIntensiveOperation(); 
     myTable.Add(item.Key, myObj); // Issue is here : breaks with exc during runtime 
    } 
    // Do something with myObj 
    // some code here 
} 

होना चाहिए कुछ एपीआई, TPL पुस्तकालय के अंदर संपत्ति की स्थापना, कि इस परिदृश्य को संभाल सकता। है?

उत्तर

18

आप System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> के लिए देख रहे हैं। नए समवर्ती संग्रह में लॉकिंग तंत्र में काफी सुधार हुआ है और समानांतर एल्गोरिदम में उत्कृष्टतापूर्वक प्रदर्शन करना चाहिए।

संपादित करें: परिणाम इस प्रकार दिखाई देंगे:

ConcurrentDictionary<T,K> cache = ...; 
Parallel.ForEach(items, (item, loopState) => 
{ 
    K value; 
    if (!cache.TryGetValue(item.Key, out value)) 
    { 
     value = SomeIntensiveOperation(); 
     cache.TryAdd(item.Key, value); 
    } 

    // Do something with value 
}); 

चेतावनी के शब्द: अगर items में तत्वों ऐसा नहीं सभी अद्वितीय item.Key है, तो SomeIntensiveOperation कि कुंजी के लिए दो बार बुलाया हो सकता है। उदाहरण में, कुंजी को SomeIntensiveOperation पर पास नहीं किया गया है, लेकिन इसका मतलब है कि "मूल्य के साथ कुछ करें" कोड कुंजी/मान ए और कुंजी/मानबी जोड़े निष्पादित कर सकता है, और केवल एक परिणाम कैश में संग्रहीत किया जाएगा (जरूरी नहीं कि पहले कुछ INTensiveOperation द्वारा गणना की गई)। को संभालने के लिए आपको समानांतर आलसी कारखाने की आवश्यकता होगी यदि यह एक समस्या है। इसके अलावा, स्पष्ट कारणों के लिए कुछ इंटरेन्टिव ऑपरेशन थ्रेड सुरक्षित होना चाहिए।

+1

@AdamRalph लगता है: जब से वह TPL पुस्तकालय वह उपयोग कर रहा है पहले से ही .NET 4 का उपयोग कर रहा है।0 –

+0

@ एडम और यासीर: सही, नए संग्रह समानांतर LINQ के साथ दिमाग में डिजाइन किए गए थे। –

+0

Yup उत्तर और टिप्पणियों के लिए धन्यवाद – Vin

1

मुझे उपयोग करने की तुलना में कोई अन्य सही विकल्प नहीं दिखता है (अधिक या कम स्पष्ट) ताले (एक सिंक्रनाइज़ हैशटेबल बस ताले के साथ सभी विधियों को ओवरराइड करता है)।

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

3

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

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

ReaderWriterLockSlim on MSDN

मुझे लगता है मैं नीचे कुछ कोड फेंक देंगे ...

ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(); 
Hashtable myTable = new Hashtable(); 
Parallel.ForEach(items, (item, loopState) => 
{ 
    cacheLock.EnterReadLock(); 
    MyObject myObj = myTable.TryGet(item.Key); 
    cacheLock.ExitReadLock(); 

    // If the object isn't cached, calculate it and cache it 
    if(myObj == null) 
    { 
     myObj = SomeIntensiveOperation(); 
     cacheLock.EnterWriteLock(); 
     try 
     { 
      myTable.Add(item.Key, myObj); 
     } 
     finally 
     { 
      cacheLock.ExitWriteLock(); 
     }   
    } 
    // Do something with myObj 
    // some code here 
} 

static object TryGet(this Hashtable table, object key) 
{ 
    if(table.Contains(key)) 
     return table[key] 
    else 
     return null; 
} 
+0

".NET Framework में दो पाठक-लेखक ताले, रीडरवाइटर लॉकस्लिम और रीडरवाइटर लॉक हैं। रीडरवाइटर लॉकस्लिम सभी नए विकास के लिए अनुशंसित है। रीडरवाइटर लॉकस्लिम रीडरवाइटर लॉक के समान है, लेकिन इसमें रिकर्सन और अपग्रेडिंग के लिए नियम सरल हैं और लॉक स्टेट डाउनग्रेडिंग। रीडरवाइटर लॉकस्लिम संभावित डेडलॉक के कई मामलों से बचाता है। इसके अलावा, रीडरवाइटर लॉकस्लिम का प्रदर्शन रीडरवाइटर लॉक से काफी बेहतर है। " –

+0

वह सलाह अच्छी लगती है, इसलिए मैंने अपना जवाब अपडेट कर दिया है। रुचि रखने वालों के लिए इस एमएसडीएन पत्रिका लेख पर एक नज़र डालें: http://msdn2.microsoft.com/en-us/magazine/cc163599.aspx – joshperry

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