मैं एक नए धागे में एक साधारण सा कोड कैसे चलाऊं?


340

मेरे पास कोड का एक सा है जिसे मुझे GUI की तुलना में एक अलग थ्रेड में चलाने की आवश्यकता है क्योंकि यह वर्तमान में कोड रन (10 सेकंड या तो) के रूप में फ़्रीज होने का कारण बनता है।

मान लें कि मैंने पहले कभी नया धागा नहीं बनाया है; C # में यह कैसे करें और .NET फ्रेमवर्क 2.0 या बाद में इसका उपयोग करने का एक सरल / मूल उदाहरण क्या है?


2
यहाँ अधिकांश उत्तर उस समय अच्छे थे, लेकिन .NET फ्रेमवर्क 4.0 में सुधार से चीजें सरल हो गईं। आप Task.Run () विधि का उपयोग कर सकते हैं, जैसा कि इस उत्तर में वर्णित है: stackoverflow.com/a/31778592/1633949
रिचर्ड द्वितीय

जवाबों:


336

पढ़ना शुरू करने के लिए अच्छी जगह जो अलबहारी है

यदि आप अपना स्वयं का धागा बनाना चाहते हैं, तो यह उतना ही सरल है जितना कि यह मिलता है:

using System.Threading;
new Thread(() => 
{
    Thread.CurrentThread.IsBackground = true; 
    /* run your code here */ 
    Console.WriteLine("Hello, world"); 
}).Start();

@EdPower, क्या यह केवल Winforms पर लागू होता है .. या यह वेब फ़ॉर्म में काम करेगा ..?
मेथडमैन

@MethodMan - हाँ, यह वेब फ़ॉर्म में काम करेगा। यहां शुरू करें:
एड पावर

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

10
@EdPower मुझे लगता है कि आपको किसी भी तरह से सावधान रहना चाहिए! एक कार्य का एक उदाहरण जिसे आप शायद मध्य-निष्पादन को समाप्त नहीं करना चाहते हैं वह है जो डेटा को डिस्क पर सहेजता है। लेकिन निश्चित रूप से, यदि आपका कार्य किसी भी समय समाप्ति के लिए उपयुक्त है, तो ध्वज ठीक है। मेरा कहना सिर्फ इतना था कि किसी को ध्वज का उपयोग करने के बारे में सावधान रहने की जरूरत है , क्योंकि आपने इसके उद्देश्य का वर्णन नहीं किया है, और इसका नामकरण आसानी से किसी को विश्वास दिला सकता है कि यह वास्तव में जो करता है, उससे कुछ और करता है।
जीरो 3

3
.NET फ्रेमवर्क के साथ 4.0+ बस Task.Run () का उपयोग करें, जैसा कि इस उत्तर में वर्णित है: stackoverflow.com/a/31778592/1633949
रिचर्ड II

193

BackgroundWorker आपके लिए सबसे अच्छा विकल्प लगता है।

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

using System.ComponentModel;
...
    private void button1_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(
        delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }

        });

        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(
        delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });

        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();
    }

ध्यान दें:

  • मैंने सादगी के लिए C # अनाम विधि का उपयोग करके सब कुछ एकल विधि में डाल दिया, लेकिन आप हमेशा उन्हें अलग-अलग तरीकों से खींच सकते हैं।
  • जीयूआई को ProgressChangedया RunWorkerCompletedहैंडलर को अपडेट करना सुरक्षित है । हालाँकि, GUI से अद्यतन करने DoWork का कारण होगा InvalidOperationException

27
System.ComponentModel का उपयोग करना; (लोगों को एक Google खोज करने से बचा सकता है, इस मददगार कोड उदाहरण के लिए धन्यवाद) +1
sooprise

@Gant नमूना कोड के लिए धन्यवाद। जब मैंने आपके कोड की कोशिश की तो ProgressChanged घटना फायरिंग नहीं थी। हालाँकि जब मैंने यहाँ भी इसी तरह के स्वीकृत उत्तर की कोशिश की [ stackoverflow.com/questions/23112676/… तो यह काम कर गया।
मार्टिन

1
@sooprise Ctrl +। इन स्थितियों में आपकी मदद करता है! (मान लें कि आप विजुअल स्टूडियो का उपयोग कर रहे हैं)
सेपरहेम

100

The ThreadPool.QueueUserWorkItem कुछ सरल के लिए बहुत आदर्श है। एकमात्र कैवेट दूसरे धागे से एक नियंत्रण तक पहुंच रहा है।

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);

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

1
+1 ध्यान दें कि प्रतिनिधि आपको मापदंडों को बड़े करीने से लपेटने की अनुमति देता है।
विल बर्कफोर्ड

कैसे कॉलबैक फ़ंक्शन के साथ ThreadPool.QueueUserWorkItem का उपयोग करें जब काम किया जाता है तो कॉल बैक हमें सूचित करेगा।
मऊ

76

त्वरित और गंदे, लेकिन यह काम करेगा:

शीर्ष पर उपयोग करना:

using System.Threading;

सरल कोड:

static void Main( string[] args )
{
    Thread t = new Thread( NewThread );
    t.Start();
}

static void NewThread()
{
    //code goes here
}

मैं बस एक नया कंसोल में एक निर्वासन के लिए फेंक दिया


8
याद रखें कि थ्रेड्स को चिह्नित किया गया IsBackground स्वचालित रूप से रनटाइम द्वारा समाप्त नहीं किया गया है। इसके लिए एप द्वारा थ्रेड मैनेजमेंट की आवश्यकता होती है। यदि आप थ्रेड को पृष्ठभूमि के रूप में चिह्नित नहीं छोड़ते हैं, तो थ्रेड निष्पादन के बाद थ्रेड आपके लिए समाप्त हो जाता है।
CmdrTallen

14
@CmdrTallen: यह बिल्कुल सही नहीं है। एक थ्रेड को IsBackground = true के रूप में चिह्नित किया गया है जिसका अर्थ है कि थ्रेड प्रक्रिया से बाहर निकलने से नहीं रोकेगा अर्थात एक प्रक्रिया बाहर निकल जाएगी जब IsBackground = false के साथ सभी थ्रेड बाहर निकल गए हों
फिल

66

यहाँ एक और विकल्प है:

Task.Run(()=>{
//Here is a new thread
});

1
यदि आप इस तरह से एक धागा बनाते हैं, तो आप इस धागे को UI थ्रेड से कैसे रोकेंगे?
slayernoah

1
@slayernoah आप इसे रद्द करने के लिए एक पैरामीटर के रूप में एक कैंसेलेशनटोकनसेन पास कर सकते हैं और थ्रेड के बाहर रद्दीकरण टोकन सेट कर सकते हैं: msdn.microsoft.com/en-us/library/dd997364(v.vs.110).aspx
Spongebob कॉमरेड

7
यह कोड आपको नया धागा रखने की गारंटी नहीं देगा। निर्णय आपके द्वारा उपयोग किए जा रहे थ्रेडपूल के वर्तमान कार्यान्वयन तक है। उदाहरण के रूप में देखें stackoverflow.com/questions/13570579/…
Giulio Caccin

3
@GiulioCaccin थ्रेडपूल के लिए अपने पूल से मौजूदा थ्रेड चुनना संभव है, लेकिन यह निश्चित रूप से एक अलग धागा है।
Spongebob कॉमरेड

40

BackgroundWorker वर्ग का उपयोग करने का प्रयास करें । आप इसे प्रतिनिधि को देते हैं कि क्या काम करना है, और जब काम पूरा हो गया है तो उसे सूचित किया जाए। MSDN पृष्ठ पर एक उदाहरण है जिसे मैंने लिंक किया है।


6
आप इसे थ्रेड क्लास के साथ निश्चित रूप से कर सकते हैं, लेकिन बैकग्राउंडवॉकर आपको थ्रेड पूरा करने और प्रगति रिपोर्टिंग के लिए तरीके देता है जो आपको अन्यथा यह पता लगाना होगा कि अपने आप को कैसे उपयोग करना है। यह मत भूलो कि आपको यूआई से बात करने के लिए इनवोक का उपयोग करना होगा!
रॉबर्ट रॉसनी

1
सावधान रहें: बैकग्राउंडवॉकर की कुछ सूक्ष्म सीमाएँ हैं, लेकिन आम के लिए "मैं दूर जाकर कुछ करना चाहता हूं और मेरे रूप को उत्तरदायी रहना है" यह शानदार है।
मेरस

10
@ मेरस, क्या आप उन सूक्ष्म सीमाओं का विस्तार कर सकते हैं?
क्रिश्चियन हुडोन

14

यदि आप एक मूल्य प्राप्त करना चाहते हैं:

var someValue;

Thread thread = new Thread(delegate()
            {                 
                //Do somthing and set your value
                someValue = "Hello World";
            });

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();

6

उस कोड को एक फ़ंक्शन में डालें (वह कोड जिसे GUI के समान थ्रेड पर निष्पादित नहीं किया जा सकता है), और उस कोड को निष्पादित करने के लिए निम्नलिखित को लागू करें।

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

थ्रेड ऑब्जेक्ट पर प्रारंभ फ़ंक्शन को कॉल करने से आपके फ़ंक्शन कॉल का निष्पादन नए थ्रेड में होगा।


3
@ user50612 आप किस बारे में बात कर रहे हैं? नया थ्रेड nameOfFunctionपृष्ठभूमि में चलेगा , न कि वर्तमान GUI थ्रेड पर। IsBackgroundसंपत्ति निर्धारित करता है कि धागा आवेदन जिंदा है या नहीं रखेंगे: msdn.microsoft.com/en-us/library/...
Zero3

5

यहां थ्रेड्स का उपयोग कैसे किया जा सकता है

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    Thread t, t2, t3;
    private void Form1_Load(object sender, EventArgs e)
    {

        CheckForIllegalCrossThreadCalls = false;

         t = new Thread(birinicBar); //evry thread workes with a new progressBar


         t2 = new Thread(ikinciBar);


         t3 = new Thread(ucuncuBar);

    }

    public void birinicBar() //to make progressBar work
    {
        for (int i = 0; i < 100; i++) {
            progressBar1.Value++;
            Thread.Sleep(100); // this progressBar gonna work faster
        }
    }

    public void ikinciBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar2.Value++;
            Thread.Sleep(200);
        }


    }

    public void ucuncuBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar3.Value++;
            Thread.Sleep(300);
        }
    }

    private void button1_Click(object sender, EventArgs e) //that button to start the threads
    {
        t.Start();
        t2.Start(); t3.Start();

    }

    private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
    {
        t.Suspend();
        t2.Suspend();
        t3.Suspend();
    }

    private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
    {
        t.Resume();
        t2.Resume();
        t3.Resume();
    }

    private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
    {
        t.Abort();
        t2.Abort();
        t3.Abort();
    }
}

3
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);

चार्ल्स आपका कोड (ऊपर) सही नहीं है। आपको पूरा होने के लिए इंतजार करने की जरूरत नहीं है। जब तक WaitHandle सिग्नल नहीं हो जाता तब तक EndInvoke ब्लॉक हो जाएगा।

यदि आप पूरा होने तक ब्लॉक करना चाहते हैं तो आपको बस जरूरत है

nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));

या वैकल्पिक रूप से

ar.AsyncWaitHandle.WaitOne();

लेकिन अगर आप ब्लॉक करते हैं तो एनओसी कॉल जारी करने का क्या मतलब है? आप बस एक तुल्यकालिक कॉल का उपयोग कर सकते हैं। एक बेहतर शर्त यह होगी कि सफाई के लिए लंबोदर को ब्लॉक और पास न किया जाए:

nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);

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


2

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

public static void DoWork()
{
    // do some work
}

public static void StartWorker()
{
    Thread worker = new Thread(DoWork);
    worker.IsBackground = true;
    worker.SetApartmentState(System.Threading.ApartmentState.STA);
    worker.Start()
}

अगर आपको UI इंटरैक्शन की आवश्यकता है, तो मैं बैकग्राउंडवॉकर क्लास की सिफारिश करूंगा।


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


1

एक अन्य विकल्प, जो प्रतिनिधियों और थ्रेड पूल का उपयोग करता है ...

'GetEnergyUsage' को एक विधि माना जाता है जो एक डेटटाइम और दूसरी डेटटाइम इनपुट तर्कों के रूप में लेता है, और एक बार ...

// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method 
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;                     
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);

1
चार्ल्स, क्या आपका कोड कार्यात्मक रूप से अलग है int usageCnt = nrgDel.Invoke(lastRunTime, procDT, null, null);? ऐसा लगता है कि यह वैसे भी नींद के साथ मौजूदा धागे को निलंबित कर देता है ... मुझे लगा कि यह जीयूआई फ्रीज के साथ कुछ भी मदद नहीं करेगा यदि आप इसे जीयूआई थ्रेड में
बुलाते हैं

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

1

.Net में अलग-अलग थ्रेड चलाने के कई तरीके हैं, प्रत्येक में अलग-अलग व्यवहार हैं। क्या आपको GUI के क्विट के बाद थ्रेड को जारी रखने की आवश्यकता है? क्या आपको थ्रेड और GUI के बीच जानकारी को पास करने की आवश्यकता है? क्या GUI को अपडेट करने के लिए थ्रेड की आवश्यकता है? क्या थ्रेड को एक कार्य करना चाहिए, फिर छोड़ देना चाहिए, या इसे जारी रखना चाहिए? इन सवालों के जवाब आपको बताएंगे कि किस विधि का उपयोग करना है।

कोड प्रोजेक्ट वेब साइट पर एक अच्छा async विधि लेख है जो विभिन्न तरीकों का वर्णन करता है और नमूना कोड प्रदान करता है।

नोट यह लेख async / प्रतीक्षा पैटर्न से पहले लिखा गया था और टास्क पैरेलल लाइब्रेरी .NET में पेश किए गए थे।


यह उस प्रकार की जानकारी है जिसकी मैं तलाश कर रहा था, लेकिन आपका उत्तर लिंक रॉट का शिकार है।
क्रिस

मुझे बताने के लिए धन्यवाद, @ क्रिस; लिंक ठीक किया गया।
डोर हाई आर्क

0

कैसे करें: फ़ाइलों के लिए खोज करने के लिए एक पृष्ठभूमि थ्रेड का उपयोग करें

आपको अन्य थ्रेड से GUI के विशिष्ट सामान तक पहुंच के साथ बहुत सावधानी बरतनी होगी (यह कई GUI टूलकिट के लिए आम है)। यदि आप प्रसंस्करण थ्रेड से GUI में कुछ अद्यतन करना चाहते हैं तो इस उत्तर को जांचें कि मुझे लगता है कि यह WinForms के लिए उपयोगी है। WPF के लिए इसे देखें (यह अपडेटप्रोएग्रेशन () विधि में घटक को कैसे छूना है, इसलिए यह अन्य थ्रेड्स से काम करेगा, लेकिन वास्तव में मुझे पसंद नहीं है कि यह Dispathcer के माध्यम CheckAccess()से करने BeginInvokeसे पहले नहीं कर रहा है , देखें और इसमें CheckAccess की खोज करें)

थ्रेडिंग पर .NET विशिष्ट पुस्तक देख रहा था और यह एक (मुफ्त डाउनलोड करने योग्य) पाया । इसके बारे में अधिक जानकारी के लिए http://www.albahari.com/threading/ देखें ।

मेरा मानना ​​है कि आपको पहले 20 पृष्ठों में नए थ्रेड के रूप में निष्पादन शुरू करने की आवश्यकता होगी और इसमें कई और हैं (जीयूआई विशिष्ट स्निपेट के बारे में निश्चित नहीं है मेरा मतलब है कि थ्रेडिंग के लिए कड़ाई से विशिष्ट है)। यह सुनकर खुशी होगी कि समुदाय इस काम के बारे में क्या सोचता है क्योंकि मैं इसे पढ़ रहा हूं। अभी के लिए मेरे लिए बहुत साफ-सुथरा लग रहा था (थ्रेडिंग के लिए .NET के विशिष्ट तरीके और प्रकार दिखाने के लिए)। इसके अलावा, यह .NET 2.0 (और प्राचीन 1.1 नहीं) को शामिल करता है जो मैं वास्तव में सराहना करता हूं।


0

मैं जेफ रिक्टर पावर थ्रेडिंग लाइब्रेरी और विशेष रूप से IAsyncEnumerator को देखने की सलाह देता हूं। चार्ली कैलवर्ट के ब्लॉग पर वीडियो देखें जहां रिक्टर एक अच्छे अवलोकन के लिए जाता है।

नाम से मत हटाओ क्योंकि यह अतुल्यकालिक प्रोग्रामिंग कार्यों को कोड करना आसान बनाता है।

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