2010-09-17 11 views
100

मैं पृष्ठभूमि थ्रेड पर चलाने के लिए एक कार्य ट्रिगर करना चाहता हूं। मैं कार्यों को पूरा करने पर इंतजार नहीं करना चाहता हूं।क्या यह एक टीपीएल कार्य वस्तु पर निपटान() को कॉल करने के लिए स्वीकार्य माना जाता है?

.net 3.5 में मैं इस किया होता:

ThreadPool.QueueUserWorkItem(d => { DoSomething(); }); 

.net 4 TPL में सुझाव दिया तरीका है। आम पैटर्न मैं सिफारिश देखा है:

Task.Factory.StartNew(() => { DoSomething(); }); 

हालांकि, StartNew() विधि एक Task वस्तु जो IDisposable लागू करता है देता है। यह उन लोगों द्वारा अनदेखा किया जाता है जो इस पैटर्न की अनुशंसा करते हैं। Task.Dispose() विधि पर एमएसडीएन दस्तावेज कहता है:

"कार्य को अपना अंतिम संदर्भ जारी करने से पहले हमेशा निपटान करें।"

आप इसे पूरा होने तक किसी कार्य पर निपटान नहीं कर सकते हैं, इसलिए मुख्य थ्रेड प्रतीक्षा और कॉल निपटान करने से पहले पृष्ठभूमि थ्रेड पर करने का बिंदु हार जाएगा। ऐसा कोई भी पूर्ण/समाप्त ईवेंट प्रतीत नहीं होता है जिसका उपयोग क्लीनअप के लिए किया जा सकता है।

कार्य वर्ग पर एमएसडीएन पृष्ठ इस पर टिप्पणी नहीं करता है, और पुस्तक "प्रो सी # 2010 ..." एक ही पैटर्न की सिफारिश करती है और कार्य निपटान पर कोई टिप्पणी नहीं करती है।

मुझे पता है कि अगर मैं इसे छोड़ देता हूं तो फाइनलइज़र इसे अंत में पकड़ लेगा, लेकिन क्या यह वापस आ जाएगा और जब मैं बहुत सारी आग कर रहा हूं तो मुझे काट देगा & इस तरह के कार्यों को भूल जाओ और फाइनलज़र थ्रेड को अभिभूत कर दिया जाए?

तो मेरी प्रश्न हैं:

  • यह स्वीकार्य है इस मामले में Task वर्ग पर Dispose() फोन नहीं करने के लिए? और यदि हां, तो जोखिम और नतीजे क्यों हैं?
  • क्या कोई दस्तावेज है जो इस पर चर्चा करता है?
  • या क्या Task ऑब्जेक्ट का निपटान करने का कोई उचित तरीका है जिसे मैंने याद किया है?
  • या आग लगने का कोई और तरीका है & टीपीएल के साथ कार्यों को भूल जाते हैं?
+0

संबंधित: (http://stackoverflow.com/q/2630488/119738) (देखें [जवाब] (http://stackoverflow.com/questions/ [करने के लिए आग और भूल जाओ सही तरीका] 2630488 /-सही तरह से करने के लिए आग और भूल-एक-अतुल्यकालिक-प्रतिनिधि/2630510 # 2630510)) –

उत्तर

88

इस in the MSDN forums के बारे में एक चर्चा है।

Task.Dispose मौजूद वजह टास्क को संभावित रूप से जब पूरा करने के लिए काम पर इंतजार कर रहे एक घटना को संभालने इस्तेमाल किया लपेटकर, में:

स्टीफन Toub, माइक्रोसॉफ्ट pfx टीम के एक सदस्य इस में क्या कहना है घटना थ्रेड को वास्तव में अवरुद्ध करना है ( कताई या संभावित के कार्य को निष्पादित करने के विरोध में) के रूप में अवरुद्ध करना है। यदि आप जो भी कर रहे हैं वह निरंतरता का उपयोग कर रहा है, तो ईवेंट इवेंट हैंडल आवंटित नहीं किया जाएगा
...
यह संभावना चीजों की देखभाल करने के लिए अंतिम रूप देने पर भरोसा करना बेहतर है।

अद्यतन (अक्टूबर 2012)
स्टीफन Toub एक ब्लॉग Do I need to dispose of Tasks? शीर्षक से जो कुछ और अधिक विस्तार देता है, और नेट 4.5 में सुधार बताते हैं पोस्ट किया गया है।

संक्षेप में: आपको Task ऑब्जेक्ट्स 99% समय का निपटान करने की आवश्यकता नहीं है।

किसी ऑब्जेक्ट को निपटाने के दो मुख्य कारण हैं: समय-समय पर, निर्धारिती तरीके से अप्रबंधित संसाधनों को मुक्त करने और ऑब्जेक्ट के अंतिमकरण को चलाने की लागत से बचने के लिए। इनमें से कोई भी Task समय की सबसे करने के लिए लागू होते हैं:

  1. नेट 4.5 के रूप में, केवल समय एक Task आवंटित आंतरिक इंतजार हैंडल (Task वस्तु में केवल अप्रबंधित संसाधन) जब आप स्पष्ट रूप से IAsyncResult.AsyncWaitHandle का उपयोग करें Task, और
  2. Task ऑब्जेक्ट में स्वयं को अंतिम रूप नहीं है; हैंडल स्वयं को किसी ऑब्जेक्ट में अंतिम रूप से लपेटा जाता है, इसलिए जब तक इसे आवंटित नहीं किया जाता है, तब तक चलाने के लिए कोई फ़ाइनलाइज़र नहीं होता है।
+3

धन्यवाद, दिलचस्प। हालांकि यह एमएसडीएन दस्तावेज के खिलाफ चला जाता है। क्या एमएस या .NET टीम से कोई आधिकारिक शब्द है कि यह स्वीकार्य कोड है। वहाँ भी मुद्दा यह है कि चर्चा के अंत में उठाया है कि "क्या हुआ अगर एक भविष्य संस्करण में कार्यान्वयन परिवर्तन" –

+0

वास्तव में, मैं सिर्फ देखा है कि उस सूत्र में उत्तर देने वास्तव में pfx टीम पर मालूम होता है, माइक्रोसॉफ्ट में काम करता है, इसलिए मुझे लगता है कि यह एक तरह का आधिकारिक उत्तर है। लेकिन इसके नीचे सुझाव है कि सभी मामलों में काम नहीं कर रहा है। यदि कोई संभावित रिसाव है तो क्या मैं बस थ्रेडपूल पर वापस लौटने के बेहतर हूं। QueueUserWorkItem जो मुझे पता है सुरक्षित है? –

+0

हां, यह बहुत अजीब बात है कि एक निपटान है जिसे आप कॉल नहीं कर सकते हैं। यदि आप http://msdn.microsoft.com/en-us/library/dd537610 पर नमूनों पर नज़र डालें।एएसपीएक्स और यहां http://msdn.microsoft.com/en-us/library/dd537609.aspx वे कार्य का निपटारा नहीं कर रहे हैं। हालांकि एमएसडीएन में कोड नमूने कभी-कभी बहुत बुरी तकनीक का प्रदर्शन करते हैं। इसके अलावा लड़के ने माइक्रोसॉफ्ट के लिए सवाल पर जवाब दिया। –

13

यह थ्रेड क्लास के समान ही समस्या है। यह 5 ऑपरेटिंग सिस्टम हैंडल का उपभोग करता है लेकिन IDISposable लागू नहीं करता है। मूल डिजाइनरों का अच्छा निर्णय, निपटान() विधि को कॉल करने के लिए निश्चित रूप से कुछ उचित तरीके हैं। आपको पहले() पहले कॉल करना होगा।

टास्क क्लास एक आंतरिक मैनुअल रीसेट ईवेंट, इस पर एक हैंडल जोड़ता है। सबसे सस्ता ऑपरेटिंग सिस्टम संसाधन कौन सा है। बेशक, इसका निपटान() विधि केवल एक ईवेंट हैंडल को रिलीज़ कर सकती है, न कि थ्रेड खपत के 5 हैंडल। Yeah, don't bother

सावधान रहें कि आपको कार्य की ISFaulted संपत्ति में रूचि रखना चाहिए। यह एक काफी बदसूरत विषय है, आप इस MSDN Library article में इसके बारे में अधिक पढ़ सकते हैं। एक बार जब आप इस तरीके से निपटने के बाद, कार्यों को निपटाने के लिए आपके कोड में भी एक अच्छी जगह होनी चाहिए।

+0

धन्यवाद हंस। वहां एक अच्छी तुलना है। –

+4

लेकिन अधिकांश मामलों में कोई कार्य 'थ्रेड' नहीं बनाता है, यह थ्रेडपूल का उपयोग करता है। – svick

-1

मैं किसी तकनीक इस पोस्ट में दिखाया गया है पर वजन को देखने के लिए अच्छा लगेगा: Typesafe fire-and-forget asynchronous delegate invocation in C#

यह एक सरल विस्तार विधि कार्यों के साथ बातचीत के सभी तुच्छ मामलों को संभालने और उस पर निपटाने कॉल करने के लिए सक्षम हो जाएगा की तरह दिखता है ।

public static void FireAndForget<T>(this Action<T> act,T arg1) 
{ 
    var tsk = Task.Factory.StartNew(()=> act(arg1), 
            TaskCreationOptions.LongRunning); 
    tsk.ContinueWith(cnt => cnt.Dispose()); 
} 
+2

बेशक 'जारी रखें' द्वारा वापस 'कार्य' उदाहरण का निपटान करने में विफल रहता है, लेकिन स्टीफन टब का उद्धरण स्वीकार्य उत्तर है: किसी भी कार्य को अवरुद्ध करने के लिए कुछ भी नहीं करने का निपटान करने के लिए कुछ भी नहीं है। – Richard

+1

जैसा कि रिचर्ड का उल्लेख है, जारी रखें (...) एक दूसरी टास्क ऑब्जेक्ट भी देता है जो तब निपटान नहीं होता है। –

+1

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

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