समानांतर। सूची में जोड़ने के साथ


80

मैं कई कार्यों को चलाने की कोशिश कर रहा हूं जो एक दूरस्थ साइट (नेटवर्क द्वारा) से जुड़ते हैं और एक सामान्य सूची वापस करते हैं। लेकिन मैं उन्हें एक साथ चलाना चाहता हूं।

उदाहरण के लिए:

public static List<SearchResult> Search(string title)
{
    //Initialize a new temp list to hold all search results
    List<SearchResult> results = new List<SearchResult>();

    //Loop all providers simultaneously
    Parallel.ForEach(Providers, currentProvider =>
    {
        List<SearchResult> tmpResults = currentProvider.SearchTitle((title));

        //Add results from current provider
        results.AddRange(tmpResults);
    });

    //Return all combined results
    return results;
}

जैसा कि मैंने देखा है, 'परिणाम' के लिए कई सम्मिलन एक ही समय में खुश हो सकते हैं ... जो मेरे आवेदन को क्रैश कर सकते हैं।

इससे कैसे बचा जा सकता है?


आप कौन से .NET वर्जन का उपयोग कर रहे हैं?
sll

4
यह कम से कम होना चाहिए। नेट 4; वहां समानांतर पेश किया गया था।
मैट मिल्स

जवाबों:


58
//In the class scope:
Object lockMe = new Object();    

//In the function
lock (lockMe)
{    
     results.AddRange(tmpResults);
}

मूल रूप से एक लॉक का मतलब है कि केवल एक ही धागे में एक ही समय में उस महत्वपूर्ण अनुभाग तक पहुंच हो सकती है।


1
लेकिन क्या होगा अगर उन परिणामों को जोड़ा जाएगा जो किसी अन्य प्रदाता से परिणाम जोड़ने की कोशिश कर रहे हैं? क्या वे संभव होने तक फेल या WAIT करेंगे?
शेखर

4
जब एक ताला होता है, तो धागा तब तक इंतजार करेगा जब तक कि उसे ताला न मिल जाए।
हैडरियन

तो मूल रूप से इसकी तरह कह रही है: अनछुए रुको!
shaharmor

8
एक मामूली बिंदु: thisलॉक ऑब्जेक्ट के लिए सबसे सुरक्षित विकल्प नहीं है। एक विशेष निजी वस्तु का उपयोग करने के लिए बेहतर है lock(resultsLock):।
हेनक होल्टरमैन

2
locksहालांकि समग्र निष्पादन समय को धीमा कर सकते हैं .. समवर्ती संग्रह से बचने के लिए बेहतर लगता है
Piotr Kula

155

आप समवर्ती संग्रह का उपयोग कर सकते हैं ।

System.Collections.Concurrentनाम स्थान कई धागे की सुरक्षित संग्रह क्लासेस में इसी प्रकार के स्थान पर इस्तेमाल किया जाना चाहिए प्रदान करता है System.Collections और System.Collections.Genericनामस्थान जब भी एक से अधिक थ्रेड समवर्ती संग्रह तक पहुँच रहे हैं।

आप उदाहरण के लिए उपयोग कर सकते हैं ConcurrentBagक्योंकि आपके पास कोई गारंटी नहीं है कि आइटम किस क्रम में जोड़े जाएंगे।

वस्तुओं के एक थ्रेड-सुरक्षित, अनियंत्रित संग्रह का प्रतिनिधित्व करता है।


हां, यह वास्तविक उत्तर है। आपको समवर्ती संग्रहों के साथ (आमतौर पर) बेहतर प्रदर्शन मिलेगा।
lkg

32

कोड पसंद करने वालों के लिए:

public static ConcurrentBag<SearchResult> Search(string title)
{
    var results = new ConcurrentBag<SearchResult>();
    Parallel.ForEach(Providers, currentProvider =>
    {
        results.Add(currentProvider.SearchTitle((title)));
    });

    return results;
}

एक लूप का उपयोग करना है: foreach (var item in currentProvider.SearchTitle((title))) results.Add(item);
एंथनी मैकग्राथ

25

.Net 4 के लिए समवर्ती संग्रह नए हैं; वे नए समानांतर कार्यक्षमता के साथ काम करने के लिए डिज़ाइन किए गए हैं।

.NET फ्रेमवर्क 4 में समवर्ती संग्रह देखें :

.NET 4 से पहले, आपको अपने खुद के सिंक्रोनाइज़ेशन मैकेनिज्म प्रदान करने होते थे, यदि कई थ्रेड एकल साझा संग्रह तक पहुंच सकते हैं। आपको कलेक्शन लॉक करना था ...

... [नया] System.Collections.Concurrent [.NET .NET में जोड़ा गया] वर्गों और इंटरफेस [...] के लिए एक सुसंगत कार्यान्वयन प्रदान करता है [...] थ्रेड्स में साझा डेटा से जुड़े बहु-थ्रेडेड प्रोग्रामिंग समस्याएं।


14

यह PLINQ AsParallelऔर का उपयोग करके स्पष्ट रूप से व्यक्त किया जा सकता है SelectMany:

public static List<SearchResult> Search(string title)
{
    return Providers.AsParallel()
                    .SelectMany(p => p.SearchTitle(title))
                    .ToList();
}

linq selectMany महान है, दुख की बात है कि linq सामान्य फॉर्च्यूनर की तुलना में धीमी है। :(
कुगन कुमार

6
माइक्रो-ऑप्टिमाइज़ न करें। ओपी निहित है कि SearchTitleएक दूरस्थ साइट से जोड़ता है। इसकी विलंबता LINQ और Foreach के बीच अंतर की तुलना में धीमी गति के कई आदेश होंगे।
डगलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.