2012-04-14 15 views
39

क्या .NET फ़ंक्शन Parallel.ForEach कॉलिंग थ्रेड को अवरुद्ध करता है? व्यवहार के रूप में मेरा अनुमान इन में से एक है:समानांतर करता है। प्रत्येक ब्लॉक के लिए?

  1. हां, यह सबसे धीमी वस्तु को रिटर्न निष्पादित करने तक अवरुद्ध करता है।
  2. नहीं, यह ब्लॉक नहीं करता है और तुरंत नियंत्रण देता है। समानांतर में चलाने के लिए आइटम पृष्ठभूमि धागे पर किए जाते हैं।

या शायद कुछ और हो रहा है, किसी को भी निश्चित रूप से पता है?

यह सवाल आया था जब एक प्रवेश कक्षा में इस लागू करने:

public class MultipleLoggingService : LoggingServiceBase 
{ 
    private readonly List<LoggingServiceBase> loggingServices; 

    public MultipleLoggingService(List<LoggingServiceBase> loggingServices) 
    { 
     this.loggingServices = loggingServices; 
     LogLevelChanged += OnLogLevelChanged; 
    } 

    private void OnLogLevelChanged(object sender, LogLevelChangedArgs args) 
    { 
     loggingServices.ForEach(l => l.LogLevel = LogLevel); 
    } 

    public override LogMessageResponse LogMessage(LogMessageRequest request) 
    { 
     if (request.LogMessage) 
      Parallel.ForEach(loggingServices, l => l.LogMessage(request)); 

     return new LogMessageResponse{MessageLogged = request.LogMessage}; 
    } 
} 

सूचना LogMessage विधि कुछ अन्य प्रवेश सेवाओं कहता है। मुझे उस हिस्से को तुरंत लौटने की ज़रूरत है, इसलिए यह कॉलिंग थ्रेड को अवरुद्ध नहीं करता है।


अद्यतन: दूसरों से टिप्पणियों के आधार पर (हमने पुष्टि की है कि व्यवहार # 1 है)। इसलिए मैं Task पुस्तकालय का उपयोग करने की सलाह ली गई और इस तरह पाश फिर से लिखा है:

  if (request.LogMessage) 
      foreach (var loggingService in loggingServices) 
       Task.Factory.StartNew(() => loggingService.LogMessage(request)); 

उत्तर

48

संख्या 1 सही है; Parallel.ForEach लूप पूरा होने तक वापस नहीं आता है। यदि आप उस व्यवहार को नहीं चाहते हैं, तो आप बस अपने लूप को Task के रूप में निष्पादित कर सकते हैं और इसे किसी अन्य थ्रेड पर चला सकते हैं।

+0

टिप के लिए धन्यवाद! क्या आपको इस संदर्भ में 'कार्य' का उपयोग करने के तरीके पर थोड़ा कोड स्निपेट होना है? धन्यवाद, पॉल –

+1

@ पॉलफ्रायर: 'कार्य टी = कार्य। कार्यफैक्टरी। स्टार्टन्यू (() => {/ * समांतर। यहां जाने के लिए * /}); ' – Richard

+6

तकनीकी रूप से, कॉलिंग थ्रेड समानांतर लूप में उपयोग किया जाता है। तो यह सिर्फ लूप पर अवरुद्ध नहीं "बर्बाद" नहीं है - इसे वर्कर थ्रेड में से एक के रूप में उपयोग किया जाता है। –

8

अपने अद्यतन, एक सामान्य foreach (में StartNew) पुन:

यह बड़े संग्रह के लिए सबसे इष्टतम नहीं हो सकता है, और आप त्रुटियों को संभालने के लिए एक बात समझ में नहीं आता।

आपके लॉगिंग सर्विसेज में शायद हजारों आइटम नहीं हैं लेकिन त्रुटि-चिह्न एक बिंदु बना हुआ है।

पर विचार करें:

Task.Factory.StartNew(() => 
{ 
    try 
    { 
     Parallel.ForEach(loggingServices, l => l.LogMessage(request)); 
    } 
    catch(SomeException ex) 
    { 
     // at least try to log it ... 
    } 
}); 
+0

आह, अच्छा बिंदु। अगर मुझे लॉगिंग सेवा विफल हो जाती है, तो त्रुटि को लॉग इन करने के लिए मुझे इसके बारे में सोचना होगा :-) –

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