BackgroundWorker बनाम बैकग्राउंड थ्रेड


166

मेरे पास पृष्ठभूमि थ्रेड कार्यान्वयन की पसंद के बारे में एक शैलीगत प्रश्न है जो मुझे विंडोज़ फॉर्म ऐप पर उपयोग करना चाहिए। वर्तमान में मेरे पास एक BackgroundWorkerफार्म है जिसमें एक अनंत (while(true))लूप है। इस लूप में मैं WaitHandle.WaitAnyथ्रेड को सूंघने के लिए उपयोग करता हूं जब तक कि कुछ ब्याज नहीं होता है। इवेंट हैंडल में से एक मैं प्रतीक्षा करता हूं एक " StopThread" घटना है ताकि मैं लूप से बाहर निकल जाऊं। इस घटना का संकेत तब दिया जाता है जब मेरे ओवरराइड से Form.Dispose()

मैं कहीं पढ़ता हूं जो BackgroundWorkerवास्तव में उन कार्यों के लिए अभिप्रेत है जो आप यूआई के साथ टाई नहीं करना चाहते हैं और एक सीमित अंत है - जैसे कि एक फ़ाइल डाउनलोड करना, या वस्तुओं के अनुक्रम को संसाधित करना। इस मामले में "अंत" अज्ञात है और केवल तभी जब खिड़की बंद हो। इसलिए मेरे BackgroundWorkerलिए इस उद्देश्य के लिए पृष्ठभूमि थ्रेड का उपयोग करना अधिक उपयुक्त होगा ?

जवाबों:


88

आपके प्रश्न की मेरी समझ से, आप BackgroundWorkerएक मानक थ्रेड के रूप में उपयोग कर रहे हैं ।

कारण है कि BackgroundWorkerचीजों के लिए अनुशंसित है कि आप यूआई धागा बाँध नहीं करना चाहती, क्योंकि यह कुछ अच्छा घटनाओं को उजागर करता है जब जीत फार्म विकास कर रही है।

थ्रेड की प्रगति पर GUI को अपडेट RunWorkerCompletedकरने के लिए इवेंट्स को इंगित करना पसंद है कि उसे क्या करना है और ProgressChangedइवेंट को पूरा करना है।

तो फिर आप इनका उपयोग नहीं कर रहे हैं , तो मुझे एक मानक थ्रेड का उपयोग करने में कोई हानि नहीं है जो आपको करने की आवश्यकता है।


एक अन्य मुद्दा जो मैं अनिश्चित हूं, मान लीजिए कि मैं उस फॉर्म को निपटाने की कोशिश कर रहा हूं, जिस पर पृष्ठभूमि का काम चल रहा है। मैं शटडाउनवेंट (मैनुअलएंडईवेंट) को संकेत देता हूं और कुछ समय बाद DoWork सुशोभित रूप से बाहर निकल जाएगा। क्या मुझे फ़ॉर्म को आगे जाने देना चाहिए और निपटान करना चाहिए, भले ही DoWork को समाप्त होने में थोड़ा अधिक समय लग सकता है, या वहाँ कोई रास्ता है (और क्या यह बेहतर है) थ्रेड के लिए। जब ​​तक यह वास्तव में बाहर नहीं निकलता है और तब तक डिस्पोज़ करने दें रूप जारी है?
फ्रेडी स्मिथ

मुझे लगता है कि BackgroundWorker.IsBusy वही है जो आप वहां ढूंढ रहे हैं।
परमेसनकॉडिस

1
केवल तभी उपयोग करें CancelAsync(और परीक्षण करें CancellationPendingकि आपका धागा कम अंतराल पर मतदान कर रहा है या नहीं, यदि आप इसके बजाय एक अपवाद को उठाना चाहते हैं, तो उपयोग करें System.Threading.Thread.Abort()जो थ्रेड ब्लॉक के भीतर एक अपवाद को उठाता है, स्थिति के लिए सही मॉडल चुनें।
ब्रेट रयान

369

मेरे कुछ विचार ...

  1. यदि आपके पास एक ही कार्य है जो पृष्ठभूमि में चलता है और UI के साथ सहभागिता करने की आवश्यकता है, तो BackgroundWorker का उपयोग करें । यूआई थ्रेड को डेटा और मेथड कॉल करने का कार्य अपने ईवेंट-आधारित मॉडल के माध्यम से स्वचालित रूप से नियंत्रित किया जाता है। BackgroundWorker से बचें अगर ...
    • आपके असेंबली में UI के साथ सीधे इंटरेक्ट नहीं है या नहीं है,
    • आप एक अग्रभूमि धागा होने की जरूरत धागा, या
    • आपको थ्रेड प्राथमिकता में हेरफेर करने की आवश्यकता है।
  2. एक थ्रेडपूल का उपयोग करेंदक्षता वांछित होने पर थ्रेड का । थ्रेडपूल थ्रेड बनाने, शुरू करने और रोकने के साथ जुड़े ओवरहेड से बचने में मदद करता है। थ्रेडपूल का उपयोग करने से बचें अगर ...
    • कार्य आपके आवेदन के जीवनकाल के लिए चलता है,
    • आपको एक अग्रभूमि धागा होने की आवश्यकता है,
    • आपको थ्रेड प्राथमिकता में हेरफेर करने की आवश्यकता है, या
    • आपको एक निश्चित पहचान (गर्भपात, निलंबन, खोज) की आवश्यकता है।
  3. लंबे समय तक चलने वाले कार्यों के लिए थ्रेड क्लास का उपयोग करें और जब आपको औपचारिक थ्रेडिंग मॉडल द्वारा पेश की जाने वाली सुविधाओं की आवश्यकता होती है, उदाहरण के लिए, अग्रभूमि और पृष्ठभूमि थ्रेड्स के बीच चयन करना, थ्रेड प्राथमिकता को प्राथमिकता देना, थ्रेड निष्पादन पर ठीक-ठीक नियंत्रण, आदि।

10
बैकग्राउंड वर्कर System.dll असेंबली और System.ComponentModel नेमस्पेस में है। Winforms पर कोई निर्भरता नहीं है।
कुगेल

17
यह सही है, लेकिन BackgroundWorkerएक इच्छुक पार्टी को थ्रेड प्रगति की रिपोर्ट करने के लिए डिज़ाइन किया गया है, जिसमें आमतौर पर एक यूआई शामिल होता है। वर्ग के लिए MSDN प्रलेखन यह बहुतायत से स्पष्ट करता है। यदि आपको पृष्ठभूमि में प्रदर्शन किए जाने वाले कार्य की आवश्यकता है, तो ThreadPoolथ्रेड का उपयोग करना पसंद करें ।
मैट डेविस

5
System.Windows.Formsविधानसभा के बारे में अपनी बात के संबंध में ; BackgroundWorkerWPF ऐप्स के लिए भी उपयोगी है और उन ऐप्स में WinForms का संदर्भ नहीं हो सकता है।
गिद्दीउपॉर्सेय

12

निम्नलिखित अतिरिक्त बिंदुओं के साथ मैट डेविस ने बहुत कुछ कहा:

मेरे लिए मुख्य विभेदक के साथ BackgroundWorkerपूरी की गई घटना के माध्यम से स्वचालित मार्शलिंग करना है SynchronizationContext। UI संदर्भ में इसका अर्थ है कि पूर्ण की गई घटना UI थ्रेड पर आग लगाती है, और इसलिए यूआई को अपडेट करने के लिए इसका उपयोग किया जा सकता है। यदि आप BackgroundWorkerUI संदर्भ में उपयोग कर रहे हैं तो यह एक प्रमुख अंतर है।

कार्य के माध्यम से निष्पादित कार्य ThreadPoolआसानी से रद्द नहीं किए जा सकते हैं (इसमें शामिल हैं ThreadPoolQueueUserWorkItemऔर प्रतिनिधि समान रूप से निष्पादित होते हैं)। इसलिए जब तक यह थ्रेड स्पिनअप के ओवरहेड से बचा जाता है, यदि आपको रद्द करने की आवश्यकता है या तो BackgroundWorker(या यूआई के बाहर अधिक संभावना) एक धागे को स्पिन करें और इसे एक संदर्भ रखें ताकि आप कॉल कर सकें Abort()


1
केवल ... उम्मीद है कि आवेदन एक थ्रेडेड टास्क को रोकने के एक साफ तरीके के बारे में बनाया गया है (

11

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


1
मुझे लगता है कि यह एक अच्छा बिंदु है। इसलिए मैं इससे जो संदेश लेता हूं वह एक पृष्ठभूमि कार्यकर्ता का उपयोग करता है यदि आपको फॉर्म के जीवनकाल के दौरान अस्थायी रूप से "थ्रेड" की आवश्यकता होती है, हालांकि अगर आपको फॉर्म के पूरे जीवनकाल के लिए पृष्ठभूमि थ्रेड की आवश्यकता होती है (जो मिनट, घंटे हो सकते हैं,) दिन ...) तो BackgroundWorker के बजाय एक थ्रेड का उपयोग करें ताकि थ्रेडपूल के उद्देश्य का दुरुपयोग न हो
freddy smith

के बारे में: "... जो चिंता का विषय हो सकता है क्योंकि उनमें से केवल एक सीमित संख्या है", क्या आप का मतलब है कि ओएस पर अन्य एप्लिकेशन को उनकी आवश्यकता हो सकती है और उसी 'पूल' से साझा कर सकते हैं?
डैन डब्ल्यू

8

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

पहले एक BackgroundWorkerविचार का उपयोग करने से पहले यदि आप किसी थ्रेड (ऐप को बंद करना, उपयोगकर्ता रद्द करना) को रद्द करना चाहते हैं, तो आपको यह तय करने की आवश्यकता है कि क्या आपके थ्रेड को रद्द करने के लिए जांचना चाहिए या यदि यह निष्पादन पर ही जोर देना चाहिए।

BackgroundWorker.CancelAsync()करने के CancellationPendingलिए सेट है, trueलेकिन अधिक कुछ भी नहीं होगा, यह तो यह लगातार जांच करने के लिए थ्रेड्स जिम्मेदारी है, यह भी ध्यान रखें कि आप इस दृष्टिकोण में एक दौड़ की स्थिति के साथ समाप्त कर सकते हैं जहां आपका उपयोगकर्ता रद्द कर दिया गया था, लेकिन परीक्षण के लिए पहले पूरा किया गया धागा CancellationPending

Thread.Abort() दूसरी ओर, थ्रेड निष्पादन के भीतर एक अपवाद फेंक देंगे जो उस थ्रेड को रद्द करने को लागू करता है, आपको इस बारे में सावधान रहना चाहिए कि क्या खतरनाक हो सकता है यदि यह अपवाद अचानक निष्पादन के भीतर उठाया गया था।

थ्रेडिंग को बहुत सावधानी से विचार करने की आवश्यकता है, चाहे कुछ भी हो, कुछ और पढ़ने के लिए:

.NET फ्रेमवर्क में समानांतर प्रोग्रामिंग सबसे अच्छे अभ्यासों को प्रबंधित करता है


5

मुझे पता था कि मुझे .NET का पता चलने से पहले थ्रेड्स का उपयोग कैसे करना है, इसलिए जब मैंने BackgroundWorkerएस का उपयोग करना शुरू किया तो इसमें कुछ उपयोग होने लगे । मैट डेविस ने महान उत्कृष्टता के साथ अंतर को संक्षेप में प्रस्तुत किया है, लेकिन मैं यह जोड़ना चाहूंगा कि कोड क्या कर रहा है यह वास्तव में समझना अधिक कठिन है, और यह डीबगिंग को कठिन बना सकता है। थ्रेड्स के पूल को काम देने के बारे में सोचने की तुलना में थ्रेड्स, IMO बनाने और बंद करने के बारे में सोचना आसान है।

मैं अभी भी अन्य लोगों की पोस्ट पर टिप्पणी नहीं कर सकता, इसलिए piers7 को संबोधित करने के उत्तर का उपयोग करने में मेरी क्षणिक उदासी को क्षमा करें

Thread.Abort();इसके बजाय का उपयोग न करें , एक घटना का संकेत दें और संकेत दिए जाने पर अपने धागे को अनुग्रहपूर्वक समाप्त करने के लिए डिज़ाइन करें। थ्रेड के निष्पादन में एक अनियंत्रित बिंदु पर Thread.Abort()उठाता है ThreadAbortException, जो अनाथ मॉनिटर, भ्रष्ट साझा स्थिति, और इसी तरह की सभी प्रकार की दुखी चीजें कर सकता है।
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx


2

अगर यह टूट नहीं गया है - इसे ठीक करें जब तक यह है ... बस मजाक कर रहा है :)

लेकिन गंभीरता से BackgroundWorker शायद आप पहले से ही क्या है के समान है, क्या आपने इसके साथ शुरुआत से शुरू किया था शायद आपने कुछ समय बचाया होगा - लेकिन इस बिंदु पर मुझे इसकी आवश्यकता नहीं है। जब तक कुछ काम नहीं कर रहा है, या आपको लगता है कि आपका वर्तमान कोड समझना मुश्किल है, तो मैं आपके पास क्या होगा।


2

मूल अंतर, जैसा आपने कहा, से GUI घटनाएँ उत्पन्न कर रहा है BackgroundWorker। यदि मुख्य GUI थ्रेड के लिए थ्रेड को डिस्प्ले अपडेट करने या इवेंट जनरेट करने की आवश्यकता नहीं है, तो यह एक साधारण थ्रेड हो सकता है।


2

मैं BackgroundWorker वर्ग के एक व्यवहार को इंगित करना चाहता हूं जो अभी तक उल्लेख नहीं किया गया था। आप Thread.IsBackground प्रॉपर्टी को सेट करके बैकग्राउंड में चलने के लिए एक सामान्य थ्रेड बना सकते हैं।

पृष्ठभूमि धागे अग्रभूमि के धागे के समान होते हैं, सिवाय इसके कि पृष्ठभूमि धागे किसी प्रक्रिया को समाप्त होने से नहीं रोकते हैं। [ ]

आप अपने प्रपत्र विंडो के निर्माता में निम्न पद्धति को कॉल करके इस व्यवहार का परीक्षण कर सकते हैं।

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = true; // <--- This will make the thread run in background
    thread.IsBackground = false; // <--- This will delay program termination

    thread.Start();
}

जब IsBackground संपत्ति सही पर सेट हो जाती है और आप विंडो बंद कर देते हैं, तो आपका आवेदन सामान्य हो जाएगा।

लेकिन जब IsBackground संपत्ति झूठी (डिफ़ॉल्ट रूप से) पर सेट हो जाती है और आप विंडो को बंद कर देते हैं, तो बस विंडो डिसैपायर हो जाएगी लेकिन प्रक्रिया अभी भी चलती रहेगी।

BackgroundWorker वर्ग पृष्ठभूमि में चलने वाले थ्रेड का उपयोग करता है।


1

एक पृष्ठभूमि कार्यकर्ता एक ऐसा वर्ग है जो एक अलग थ्रेड में काम करता है, लेकिन यह अतिरिक्त कार्यक्षमता प्रदान करता है जो आपको एक साधारण थ्रेड के साथ नहीं मिलता है (जैसे कार्य प्रगति की हैंडलिंग)।

यदि आपको पृष्ठभूमि कार्यकर्ता द्वारा दी गई अतिरिक्त सुविधाओं की आवश्यकता नहीं है - और ऐसा लगता है कि आप नहीं हैं - तो एक थ्रेड अधिक उपयुक्त होगा।


-1

मेरे लिए सबसे बुरा यह है कि दृश्य स्टूडियो डिजाइनर केवल आपको बैकग्राउंडर्स और टाइमर का उपयोग करने की अनुमति देता है जो वास्तव में सेवा परियोजना के साथ काम नहीं करते हैं।

यह आपको अपनी सेवा पर नीट ड्रैग और ड्रॉप कंट्रोल देता है लेकिन ... इसे लागू करने का प्रयास भी न करें। काम नहीं करेगा।

सेवाएँ Services: ओनली यूज़ System.Timers.Timer System.Windows.Forms.Timer टूलबॉक्स में उपलब्ध होने के बावजूद काम नहीं करेगा

सेवाएँ: BackgroundWorkers तब काम नहीं करेगा जब यह सेवा के रूप में चल रहा हो। System.Threading.ThreadPools इसके बजाय या Async कॉल का उपयोग करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.