2010-06-29 18 views
5

हैलो मैं एक निर्माता और एक उपभोक्ता सहयोग करने के लिए धागे करना चाहते हैं। उपभोक्ता धीमा है, और निर्माता बहुत तेज है और विस्फोटों में काम करता है।C# अंतर-धागा संचार

उदाहरण के लिए उपभोक्ता 20 सेकंड प्रति एक संदेश संसाधित कर सकते हैं, और निर्माता एक सेकंड में 10 संदेश उत्पादन कर सकते हैं, लेकिन यह एक लंबे समय के बारे में एक बार होता है, जबकि इतने उपभोक्ता मिल सकते हैं।

मैं चाहता हूँ की तरह कुछ:

Stream commonStream; 
AutoResetEvent commonLock; 

void Producer() 
{ 
    while (true) 
    { 
    magic.BlockUntilMagicAvalible(); 
    byte[] buffer = magic.Produce(); 
    commonStream.Write(buffer); 
    commonLock.Set(); 
    } 
} 

void Consumer() 
{ 
    while(true) 
    { 
    commonLock.WaitOne(); 
    MagicalObject o = binarySerializer.Deserialize(commonStream); 
    DoSomething(o); 
    } 
} 
+0

नेट किस संस्करण का उपयोग कर रहे हैं, वहाँ कुछ नई चीजें वास्तव में इस सामग्री –

+0

नेट 3 के लिए 4 से कर रहे हैं।5; टिप्पणियां लंबाई में कम से कम 15 वर्ण होने चाहिए। –

उत्तर

1

मैं निम्नलिखित लेख पढ़ने होगा कि वे अपनी समस्या का वर्णन। असल में आपको काम की अपनी इकाई के लिए सही अलगाव नहीं मिल रहा है।

http://blogs.msdn.com/b/ricom/archive/2006/04/24/582643.aspx http://blogs.msdn.com/b/ricom/archive/2006/04/26/584802.aspx

+0

हाँ इसकी तरह जो मैं चाहता हूं मैं लिख सकता हूं ... –

11

आप नेट 4.0 या उच्चतर है, तो आप इसे एक BlockingCollection

int maxBufferCap = 500; 
BlockingCollection<MagicalObject> Collection 
          = new BlockingCollection<MagicalObject>(maxBufferCap); 
void Producer() 
{ 
    while (magic.HasMoreMagic) 
    { 
     this.Collection.Add(magic.ProduceMagic()); 
    } 
    this.Collection.CompleteAdding(); 
} 

void Consumer() 
{ 
    foreach (MagicalObject magicalObject in this.Collection.GetConsumingEnumerable()) 
    { 
     DoSomthing(magicalObject); 
    } 
} 

foreach लाइन का उपयोग करता है, तो वहाँ बफर में कोई डाटा नहीं है सो जाएगा द्वारा इस तरह से कर सकते हैं, जब संग्रह में कुछ जोड़ा जाता है तो यह स्वचालित रूप से इसे स्वयं भी जगाएगा।

कारण मैं अधिकतम बफर सेट करते हैं तो अपने निर्माता उपभोक्ता आप स्मृति का एक बहुत लेने के रूप में अधिक से अधिक वस्तुओं संग्रह करने के लिए में डाल करने के अंत हो सकता है की तुलना में बहुत तेजी से होता है। जैसा कि आप अवरुद्ध संग्रह जब बफर आकार तक एक आइटम उपभोक्ता द्वारा संग्रह से हटा दिया गया अवरुद्ध कर देगा निर्माता पर Add कॉल तक पहुँच जाता है बनाने के एक अधिकतम बफ़र आकार सेट करके।

BlockingCollection कक्षा का एक और बोनस यह है कि इसमें जितने चाहें उतने उत्पादक और उपभोक्ता हो सकते हैं, इसे 1: 1 अनुपात होने की आवश्यकता नहीं है। DoSomthing इसका समर्थन करता है, तो आप (या यहां तक ​​Parallel.ForEach का उपयोग करें और डेटा स्रोत के रूप गणनीय लेने का उपयोग)

void ConsumersInParalell() 
{ 
    //This assumes the method signature of DoSomthing is one of the following: 
    // Action<MagicalObject> 
    // Action<MagicalObject, ParallelLoopState> 
    // Action<MagicalObject, ParallelLoopState, long> 
    Paralell.ForEach(this.Collection.GetConsumingEnumerable(), DoSomthing); 
} 
+2

ध्यान दें कि टीपीएल को .NET 3.5 पर वापस भेज दिया गया है: http://codeblog.theg2.net/2010/02/tpl-and-parallelforeach-in- net-35-using.html –

0

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

System.Timers.Timer consumerTimer; 
Queue<byte[]> queue = new Queue<byte[]>(); 

void Producer() 
{ 
    consumerTimer = new System.Timers.Timer(1000); 
    consumerTimer.Elapsed += new System.Timers.ElapsedEventHandler(consumerTimer_Elapsed); 
    while (true) 
    { 
     magic.BlockUntilMagicAvailable(); 
     lock (queue) 
     { 
      queue.Enqueue(magic.Produce()); 
      if (!consumerTimer.Enabled) 
      { 
       consumerTimer.Start(); 
      } 
     } 
    } 
} 

void consumerTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    while (true) 
    { 
     consumerTimer.Stop(); 
     lock (queue) 
     { 
      if (queue.Count > 0) 
      { 
       DoSomething(queue.Dequeue()); 
      } 
      else 
      { 
       break; 
      } 
     } 
    } 
} 
+0

आपका स्निपेट थ्रेड सुरक्षित नहीं है ... और मेरा मतलब कोई मतदान नहीं है –

+0

इसके बारे में धागा सुरक्षित नहीं है? और यह मतदान नहीं करता है - टाइमर एक शॉट है जो निर्माता केवल कतार में जोड़ता है जब सक्रिय होता है। –

-1

मैं म्यूटेक्स का उपयोग करता हूं। विचार यह है कि दोनों अलग-अलग धागे में चलते हैं। कंज्यूमर थ्रेड एक म्यूटेक्स द्वारा लॉक किया गया है, जहां यह निर्माता द्वारा रिलीज होने तक अनिश्चित काल तक बैठेगा। इसके बाद निर्माता को जारी रखने के लिए समानांतर में डेटा को संसाधित किया जाएगा। पूर्ण होने पर उपभोक्ता फिर से लॉक हो जाएगा।

(कोड धागा शुरू करते हैं, और अन्य गुणवत्ता बिट्स संक्षिप्तता के लिए छोड़ दिए गए हैं।)

// Pre-create mutex owned by Producer thread, then start Consumer thread. 
Mutex mutex = new Mutex(true); 
Queue<T> queue = new Queue<T>(); 

void Producer_AddData(T data) 
{ 
    lock (queue) { 
    queue.Enqueue(GetData()); 
    } 

    // Release mutex to start thread: 
    mutex.ReleaseMutex(); 
    mutex.WaitOne(); 
} 

void Consumer() 
{ 
    while(true) 
    { 
    // Wait indefinitely on mutex 
    mutex.WaitOne(); 
    mutex.ReleaseMutex(); 

    T data; 
    lock (queue) { 
     data = queue.Dequeue(); 
    } 
    DoSomething(data); 
    } 

}

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

+0

'ब्लॉकिंग कोलेक्शन' का उपयोग करना बहुत बेहतर है। सबसे पहले, यह अधिक स्पष्ट है जब यह म्यूटेक्स का उपयोग करने से सही है, और आपके मॉडल के विपरीत निर्माता और उपभोक्ता समानांतर में काम कर सकता है; आप यह सुनिश्चित कर रहे हैं कि आपका कोड * या तो * उत्पादन * या * उपभोग करने वाला है, लेकिन दोनों कभी नहीं। यह एक से अधिक उत्पादकों या एक से अधिक उपभोक्ताओं को भी अच्छी तरह से स्केल नहीं करता है, एक ब्लॉकिंग संग्रह के विपरीत जहां ऐसा करना तुच्छ है। आप एक अधिक जटिल म्यूटेक्स आधारित दृष्टिकोण का उपयोग कर सकते हैं जिसमें अवरुद्ध संग्रह के लाभ थे, लेकिन यह * काम * का होगा, और बहुत कम पठनीय/रखरखाव योग्य होगा। – Servy

+0

ब्लॉकिंग कोलेक्शन मेरे लिए उपलब्ध नहीं है क्योंकि मैं 4.5 नहीं चला सकता। अगर मैं कर सकता तो यह शायद सही समाधान होगा। हालांकि यह कोड समानांतर में चलता है। मैं स्पष्ट नहीं हो सकता था, लेकिन दोनों अलग-अलग धागे में हैं। मैं इसे एक थ्रेड पर भारी SQL क्वेरी चलाने के लिए उपयोग करता हूं, जबकि किसी अन्य धागे पर डेटा एकत्र करता है और यह मेरे लिए अच्छा काम करता है। – Ben

+0

ब्लॉकिंग कोलेक्शन 4.0 में जोड़ा गया था, 4.5 नहीं। – Servy

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