2012-02-23 9 views
21

में एक नया धागा शुरू करना मेरे पास ऑब्जेक्ट्स की एक सूची है और मैं उस सूची पर लूप करना चाहता हूं और वर्तमान ऑब्जेक्ट में गुजरने वाला एक नया थ्रेड शुरू करना चाहता हूं।फ़ोरैच लूप

मैंने एक उदाहरण लिखा है जो मैंने सोचा था कि यह क्या करना चाहिए, लेकिन यह काम नहीं कर रहा है। विशेष रूप से, ऐसा लगता है जैसे थ्रेड प्रत्येक पुनरावृत्ति पर ओवरराइट हो रहे हैं। यह वास्तव में मुझे समझ में नहीं आता है क्योंकि मैं हर बार एक नया थ्रेड ऑब्जेक्ट बना रहा हूं।

यह परीक्षण कोड मैंने लिखा

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestClass t = new TestClass(); 
     t.ThreadingMethod(); 
    } 
} 

class TestClass 
{ 
    public void ThreadingMethod() 
    { 
     var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") }; 

     foreach(MyClass myObj in myList) 
     { 
      Thread myThread = new Thread(() => this.MyMethod(myObj)); 
      myThread.Start(); 
     } 
    } 

    public void MyMethod(MyClass myObj) { Console.WriteLine(myObj.prop1); } 
} 

class MyClass 
{ 
    public string prop1 { get; set; } 

    public MyClass(string input) { this.prop1 = input; } 
} 
है

मेरी मशीन पर उत्पादन

test2 
test2 

है, लेकिन मैं यह उम्मीद

test1 
test2 

होने के लिए मैं धागा लाइनों को बदलने की कोशिश की

ThreadPool.QueueUserWorkItem(x => this.MyMethod(myObj)); 

लेकिन धागे में से कोई भी शुरू नहीं हुआ।

मुझे लगता है कि मुझे केवल गलतफहमी है कि धागे कैसे काम करते हैं। क्या कोई मुझे सही दिशा में इंगित कर सकता है और मुझे बता सकता है कि मैं क्या गलत कर रहा हूं?

+1

आपका जीवन हो जाएगा यदि आप .NET 3.5 में समांतर समांतर एक्सटेंशन लाइब्रेरी को देखते हैं तो बहुत आसान है। शुरू करने के लिए यहां एक स्थान दिया गया है: http://msdn.microsoft.com/en-us/library/dd460693%28VS.100%29.aspx – DOK

+0

http://www.albahari.com/threading/ –

उत्तर

38

ऐसा इसलिए है क्योंकि आप गलत दायरे में एक चर पर बंद कर रहे हैं। Closing over the loop variable considered harmful

+1

आपने मुझे इसे हराया ! –

+0

यह एक त्वरित प्रतिक्रिया थी। वाह। – BlueM

+1

गह, मैं खुद को लात मार रहा हूं क्योंकि मैं वास्तव में [इस सवाल] (http://stackoverflow.com/q/8898925/817630) को पढ़ता हूं जो उत्तर है। मैंने एरिक के ब्लॉग पोस्ट पर भी एक नज़र डाली।यह इंगित करने के लिए धन्यवाद कि मुझे खुद को क्या याद रखना चाहिए था। –

3

समस्या यह है कि आप सबसे वर्तमान मूल्य का उपयोग कर रहे है:

foreach(MyClass myObj in myList) 
    { 
     MyClass tmp = myObj; // Make temporary 
     Thread myThread = new Thread(() => this.MyMethod(tmp)); 
     myThread.Start(); 
    } 

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

foreach(MyClass myObj in myList) 
{ 
    MyClass localCopy = myObj; 
    Thread myThread = new Thread(() => this.MyMethod(localCopy)); 
    myThread.Start(); 
} 
2

रीड के उत्तर (+1) के साथ सहमत हैं।

मैं जोड़ता हूं कि यदि आप .NET 4 पर हैं, तो आप समस्या के इस वर्ग को हल करने के लिए कार्य समांतर लाइब्रेरी को देखना चाह सकते हैं। विशेष रूप से इस मामले के लिए, Parallel.ForEach() पर एक नज़र डालें।

+1

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

1

यदि अनुक्रम में कोई फर्क नहीं है की तुलना में

Parallel.ForEach(myList, obj => this.MyMethod(obj)); 

Write a Simple Parallel.ForEach Loop

+0

समांतर। अपने आप के लिए, एक अवरुद्ध विधि है, जहां ओपी "आग और भूल" है - इसलिए इसका उपयोग करने में एक कार्यात्मक अंतर है। यह इस मामले में उपयुक्त नहीं हो सकता है (कम से कम इसे एक कार्य के भीतर नहीं डाले बिना) –

1

के लिए जाना मैं इस तरह से पसंद करते हैं:

public void ThreadingMethod() 
{ 
    var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") }; 


Parallel.ForEach(myList, new ParallelOptions() { MaxDegreeOfParallelism = 100 }, 
     (myObj, i, j) => 
     { 
      MyMethod(myObj); 
     }); 

} 
नहीं

हालांकि परीक्षण किया ....

+0

समांतर। के लिए ओपी की विधि के मुकाबले एक अलग कार्यात्मक व्यवहार है। मूल कोड में "आग और भूलना" व्यवहार होता है, जबकि यह संचालन पूर्ण होने तक कॉलिंग थ्रेड को अवरुद्ध कर देगा। इसके अलावा, मैं MaxDegreeOfParallelism को सेट करने की अनुशंसा नहीं करता जब तक ऐसा करने का कोई विशिष्ट कारण न हो। –

+0

@ReedCopsey - मुझे लगता है कि आप बस इसे मान रहे हैं। समानांतर का उपयोग करना। फोरएच हमेशा आपके आवेदन में एक प्रोपर थ्रेडिंग को लागू करने के लिए एक पसंदीदा तरीका है, खासकर यदि आपके पास बहुत सी चीजें हैं जिन्हें आप संसाधित करना चाहते हैं (एक ही समय में) और आपके पास सरल थ्रेड() का उपयोग करने के लिए पर्याप्त संसाधन नहीं हैं। यदि वह आपकी सुझाई गई विधि के साथ 1000 धागे का उपयोग करता है तो इसका बहुत खराब कार्यान्वयन। – SolidSnake

+0

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

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