2012-06-22 13 views
8

क्या कोई जानता है कि PLINQ में समानांतर कार्यक्षमता लौटने वाले एक्सटेंशन फ़ंक्शन को कैसे लिखना है?मैं PLINQ के लिए थ्रेड-जागरूक एक्सटेंशन फ़ंक्शन कैसे लिखूं?

अधिक विशेष रूप से, मुझे निम्न समस्या है: मैं एक PLINQ क्वेरी के भीतर एक रूपांतरण करना चाहता हूं जिसके लिए एक इंजन की आवश्यकता है, जिसका निर्माण महंगा है और जिसे समवर्ती रूप से उपयोग नहीं किया जा सकता है। जो बहुत महंगा है

var result = source.AsParallel().Select ((i) => { var e = new Engine(); return e.Process(i); }) 

यहाँ, इंजन प्रति आइटम एक बार बनाई गई है,:

मैं निम्नलिखित कर सकता है।

मैं चाहता हूं कि इंजन प्रति थ्रेड पर एक बार बनाया जाए।

सकल के साथ, मैं मैं क्या

// helper class: engine to use plus list of results obtained in thread so far 
class EngineAndResults { 
    public Engine engine = null; 
    public IEnumerable<ResultType> results; 
} 

var result = source.AsParallel().Aggregate (

    // done once per block of items (=thread), 
    // returning an empty list, but a new engine 
    () => new EngineAndList() { 
     engine = new Engine(), 
     results = Enumerable.Empty<ResultType>() 
    }, 

    // we process a new item and put it to the thread-local list, 
    // preserving the engine for further use 
    (engineAndResults, item) => new EngineAndResults() { 
     engine = engineAndResults.engine, 
     results = Enumerable.Concat (
      engineAndResults.results, 
      new ResultType [] { engineAndResults.engine.Process (item) } 
     ) 
    }, 

    // tell linq how to aggregate across threads 
    (engineAndResults1, engineAndResults2) => new EngineAndResults() { 
     engine = engineAndResults1.engine, 
     results = Enumerable.Concat (engineAndResults1.results, engineAndResults2.results) 
    }, 

    // after all aggregations, how do we come to the result? 
    engineAndResults => engineAndResults.results 
); 

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

मैं किसी को किसी भी विचार कैसे इस लक्ष्य को हासिल करने के लिए है की तरह

var result = source.AsParallel() 
        .SelectWithThreadwiseInitWhichIAmLookingFor (
         () => new Engine(), 
         (engine, item) => engine.Process (item) 
      ) 

कुछ जानना चाहेंगे?

उत्तर

5

आप ऐसा करने के लिए ThreadLocal<T> का उपयोग कर सकते हैं। कुछ ऐसा:

var engine = new ThreadLocal<Engine>(() => new Engine()); 
var result = source.AsParallel() 
        .Select(item => engine.Value.Process(item)); 
+0

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

+0

मुझे लगता है कि यह काम नहीं करता है, क्योंकि आप प्रत्येक पुनरावृत्ति के लिए एक नया 'थ्रेडलोकल' बना रहे थे, इसलिए उसी थ्रेड पर निष्पादित पुनरावृत्तियों के लिए कोई साझाकरण नहीं हो सका। उसी थ्रेड पर चलने वाले सभी पुनरावृत्तियों को 'थ्रेडलोकल' के समान उदाहरण की आवश्यकता होती है। – svick

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