2016-02-10 7 views
5

मेरे पास एक तृतीय पक्ष घटक है जो स्पिन अप करने के लिए "महंगा" है। यह घटक थ्रेड सुरक्षित नहीं है। कहा गया है कि डब्ल्यूसीएफ सेवा (अब के लिए) के अंदर घटक होस्ट किया गया है, इसलिए ... जब भी कॉल में सेवा आती है तो मुझे घटक को नया करना होगा।"फिक्स्ड"/"लोड बैलेंस्ड" सी # थ्रेड पूल?

इसके बजाय मैं जो करना चाहता हूं उसके पास 16 धागे का एक पूल है जो प्रत्येक घटक की अपनी प्रतिलिपि बनाता है और विधि को कॉल करने के लिए एक तंत्र है और इसे 16 धागे में से एक में वितरित किया गया है और मूल्य वापस आ गया।

तो कुछ सरल की तरह:

var response = threadPool.CallMethod(param1, param2); 

के रूप में मैं आगे बढ़ने के लिए प्रतिक्रिया की जरूरत है जब तक यह एक प्रतिक्रिया मिलती कॉल ब्लॉक करने के लिए के लिए इसके ठीक।

कोई सुझाव? हो सकता है कि मैं इसे ओवरइंक कर रहा हूं और ConcurrentQueue जो 16 धागे से सर्विस किया जाता है, वह काम करेगा, लेकिन अब सुनिश्चित करें कि विधि वापसी मूल्य कॉलर को वापस कैसे किया जाएगा?

+0

घटक के बारे में अधिक जानना चाहते हैं। 1) क्या यह एक COM घटक है? 2) आप डब्ल्यूसीएफ सेवा कैसे होस्ट करते हैं? आईआईएस? एक विंडोज सेवा के अंदर? कंसोल ऐप? 3) डब्ल्यूसीएफ सेवा का इंस्टेंस कंट्रोल क्या है? सिंगलटन? प्रति कॉल? प्रति सत्र? – MickyD

+2

@MickyD ने जो कहा है उसके शीर्ष पर, घटक का एक नया उदाहरण बनाने के लिए कॉल को थ्रेड करना आपके थ्रेड सुरक्षा समस्या को हल नहीं करता है (मुझे लगता है कि यह वास्तव में इसे और भी खराब बनाता है)। – AWinkle

+3

ऐसा लगता है कि आपको वास्तव में क्या चाहिए, एक ऑब्जेक्ट पूल है, न कि थ्रेड पूल। –

उत्तर

2

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

मैं अपनी स्थिति सिर्फ एक एकलThreadLocal या धागे स्थिर है कि आपके महंगा वस्तु के साथ एक बार प्रारंभ जायेगा का उपयोग किया जाता है में क्या करना होगा क्या। उसके बाद यह थ्रेड पूल थ्रेड के लिए उपलब्ध होगा।

यह मानते हुए कि आपकी वस्तु एमटीए थ्रेड पर ठीक है; मुझे लगता है कि यह आपकी पोस्ट से है क्योंकि ऐसा लगता है जैसे चीजें वर्तमान काम कर रही हैं, लेकिन बस धीमी है।

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

+0

हाँ, मुझे लगता है कि मैं जो खोज रहा हूं वह एक ऑब्जेक्ट पूल है, न कि थ्रेड पूल। वस्तु धागा सुरक्षित नहीं है। यदि एकाधिक धागे एक ही उदाहरण तक पहुंचते हैं, तो यह क्रैश हो जाता है। थ्रेडलोकल डब्लूसीएफ सेवा के रूप में उपयोगी नहीं है और धागे को नष्ट कर देता है। – SledgeHammer

+0

क्या आपने वास्तव में अभ्यास में परीक्षण किया है? यह मामला अच्छी तरह से हो सकता है, लेकिन इस लड़के ने इसे थ्रेड पूल से धागे खींच लिया: http://stackoverflow.com/questions/5288991/destroy-a-wcf-thread। वह कहता है कि राज्य को स्टोर करने के लिए थ्रेड स्टेटिक्स का उपयोग न करें, लेकिन यहां आप राज्य को संग्रहित नहीं कर रहे हैं। – briantyler

2

सबसे पहले और सबसे महत्वपूर्ण, मैं @briantyler से सहमत हूं: ThreadLocal<T> या थ्रेड स्थैतिक फ़ील्ड शायद आप जो चाहते हैं। आपको इसके साथ शुरुआती बिंदु के रूप में जाना चाहिए और अन्य विकल्पों पर विचार करना चाहिए यदि यह आपकी आवश्यकताओं को पूरा नहीं करता है।

एक जटिल लेकिन लचीला विकल्प एक सिंगलटन ऑब्जेक्ट पूल है। इसकी सबसे सरल रूप में अपने पूल प्रकार इस तरह दिखेगा:

public sealed class ObjectPool<T> 
{ 
    private readonly ConcurrentQueue<T> __objects = new ConcurrentQueue<T>(); 
    private readonly Func<T> __factory; 

    public ObjectPool(Func<T> factory) 
    { 
     __factory = factory; 
    } 

    public T Get() 
    { 
     T obj; 
     return __objects.TryDequeue(out obj) ? obj : __factory(); 
    } 

    public void Return(T obj) 
    { 
     __objects.Enqueue(obj); 
    } 
} 

यह बहुत उपयोगी प्रतीत नहीं होता है अगर आप, आदिम वर्ग या structs (यानी ObjectPool<MyComponent>) के मामले में प्रकार T की सोच रहे हैं पूल इसमें कोई थ्रेडिंग नियंत्रण नहीं है। लेकिन आप या Task<T> मोनैड के लिए अपने प्रकार T को प्रतिस्थापित कर सकते हैं, और वही प्राप्त कर सकते हैं जो आप चाहते हैं।

पूल initialisation:

Func<Task<MyComponent>> factory =() => Task.Run(() => new MyComponent()); 
ObjectPool<Task<MyComponent>> pool = new ObjectPool<Task<MyComponent>>(factory); 

// "Pre-warm up" the pool with 16 concurrent tasks. 
// This starts the tasks on the thread pool and 
// returns immediately without blocking. 
for (int i = 0; i < 16; i++) { 
    pool.Return(pool.Get()); 
} 

उपयोग:

// Get a pooled task or create a new one. The task may 
// have already completed, in which case Result will 
// be available immediately. If the task is still 
// in flight, accessing its Result will block. 
Task<MyComponent> task = pool.Get(); 

try 
{ 
    MyComponent component = task.Result; // Alternatively you can "await task" 

    // Do something with component. 
} 
finally 
{ 
    pool.Return(task); 
} 

यह विधि एक ThreadLocal या धागे स्थिर क्षेत्र में अपने घटक को बनाए रखने से कहीं अधिक जटिल है, लेकिन आप कुछ सीमित की तरह कल्पना करने की ज़रूरत है, तो पूल किए गए उदाहरणों की संख्या, पूल अमूर्तता काफी उपयोगी हो सकती है।

संपादित

बेसिक "एक्स उदाहरणों का सेट स्थायी" एक Get साथ पूल कार्यान्वयन पूल एक बार ब्लॉक सूखा किया गया है जो:

public sealed class ObjectPool<T> 
{ 
    private readonly Queue<T> __objects; 

    public ObjectPool(IEnumerable<T> items) 
    { 
     __objects = new Queue<T>(items); 
    } 

    public T Get() 
    { 
     lock (__objects) 
     { 
      while (__objects.Count == 0) { 
       Monitor.Wait(__objects); 
      } 

      return __objects.Dequeue(); 
     } 
    } 

    public void Return(T obj) 
    { 
     lock (__objects) 
     { 
      __objects.Enqueue(obj); 

      Monitor.Pulse(__objects); 
     } 
    } 
} 
+0

हाँ, मुझे लगता है कि यह जाने का रास्ता है। मुझे ऑब्जेक्ट पूल को एक्स इंस्टेंस के निश्चित सेट के लिए ट्विक करने की आवश्यकता है, फिर उन्हें बिना किसी सीमा के फ्लाई पर बनाएं। – SledgeHammer

+0

@SledgeHammer, उस स्थिति में आप अपने ऑब्जेक्ट पूल के रूप में 'अवरुद्ध चयन ' का उपयोग कर सकते हैं। यदि आप कभी ऐसी परिस्थिति में भाग लेते हैं जहां सभी पूल किए गए ऑब्जेक्ट्स को किराए पर लिया गया है, तो अगला उपभोक्ता 'टेक() 'पर रोक देगा जब तक कि एक उदाहरण वापस नहीं किया जाता है (' जोड़ें 'के माध्यम से)। –

+0

मैं एक पूल पर भी विचार करूंगा जहां 'वापसी' वापस लौटाए गए उदाहरण को छोड़ देता है यदि पूल की आवृत्ति गणना वांछित मूल्य से आगे बढ़ती है। यह बिल्कुल आवश्यक होने पर नए उदाहरण आवंटित किए जाने की अनुमति देता है, लेकिन कोई अधिशेष एकत्रित किया जाएगा, इस प्रकार असंबद्ध विकास को रोक देगा। –

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