15

अधिक नौसिखिया प्रश्न:यह समानांतर क्यों है। प्रत्येक कोड प्रोग्राम को फ्रीज करता है?

यह कोड मुख्य विंडो में सूची से कई प्रॉक्सी पकड़ता है (मैं यह नहीं समझ सकता कि विभिन्न कार्यों के बीच चर बनाने के लिए कैसे किया जा सकता है) और प्रत्येक पर एक चेक (सरल httpwebrequest) और फिर उन्हें EndProxies नामक एक सूची में जोड़ता है।

किसी कारण से जब मैं स्टार्ट बटन दबाता हूं, तो पूरा प्रोग्राम लटकता है। मैं इस धारणा के तहत था कि समानांतर यूआई थ्रेड को छोड़कर प्रत्येक कार्रवाई के लिए समानांतर बनाता है ताकि यह उत्तरदायी हो?

private void start_Click(object sender, RoutedEventArgs e) 
     { 
      // Populate a list of proxies 
      List<string> proxies = new List<string>(); 
      List<string> finishedProxies = new List<string>(); 

      foreach (string proxy in proxiesList.Items) 
      { 
       proxies.Add(proxy); 
      } 

      Parallel.ForEach<string>(proxies, (i) => 
      { 
       string checkResult; 
       checkResult = checkProxy(i); 

       finishedProxies.Add(checkResult); 
       // update ui 
       /* 
       status.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(
        delegate() 
        { 
         status.Content = "hello" + checkResult; 
        } 
       )); */ 
       // update ui finished 


       //Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i)); 
      }); 


     } 

मैं कोड है कि बाहर टिप्पणी की है Parallel.Foreach अंदर यूआई परिवर्तन करने के लिए उपयोग करने की कोशिश की है और बाद प्रारंभ बटन दबाया जाता है यह कार्यक्रम फ्रीज बनाता है। यह मेरे लिए पहले काम करता है लेकिन मैंने थ्रेड क्लास का इस्तेमाल किया।

मैं समानांतर के अंदर से यूआई कैसे अपडेट कर सकता हूं। Foreach और मैं समानांतर कैसे बना सकता हूं। Foreach काम करता है ताकि यह काम करते समय UI को फ्रीज न कर सके? अपने कोड के साथ

Here's the whole code.

+2

आप यूआई थ्रेड को इनवॉक अनुरोधों के साथ पंपलिंग कर रहे हैं, यह अब अपने नियमित कर्तव्यों को पूरा करने के लिए नहीं मिलता है। यूआई को पुनर्स्थापित करने की तरह। कम से कम पृष्ठभूमि को प्राथमिकता कम करें। –

+0

@ dsp_099b "यह मेरे लिए पहले काम करता है लेकिन मैंने थ्रेड क्लास का उपयोग किया" के तहत आपका क्या मतलब है? – Fulproof

उत्तर

15

आपको अपने यूआई थ्रेड में समांतर प्रसंस्करण शुरू नहीं करना चाहिए। this page में "यूआई थ्रेड पर समानांतर लूप निष्पादित करने से बचें" शीर्षक के तहत उदाहरण देखें।

अद्यतन: या, आप बस एक नया धागा मैनुअल बना सकते हैं और अंदर प्रसंस्करण शुरू कर सकते हैं जैसा कि मैंने देखा है कि आपने किया है। उसमें कुछ भी गलत नहीं है।

इसके अलावा, जिम मिशेल बताते हैं, आप एक साथ कई धागे से सूचियों तक पहुंच रहे हैं, इसलिए वहां दौड़ की स्थिति है। List के लिए या तो ConcurrentBag को प्रतिस्थापित करें, या प्रत्येक बार जब आप उन्हें एक्सेस करते हैं तो lock कथन के अंदर सूचियां लपेटें।

+4

'सूची' के लिए "विकल्प 'ConcurrentBag' के तहत आपका क्या मतलब है? ... क्या आप वास्तव में "विकल्प 'सूची' का अर्थ 'ConcurrentBag'' से करते थे? – Fulproof

+1

@ फ़ुलप्रूफ: मेरा मानना ​​है कि सही अंग्रेजी "ए * के लिए विकल्प ए * * ==" विकल्प बी * के साथ * ए "है। – Jon

+1

["एक चीज़ (ए) के लिए एक चीज (ए) विकल्प (बी)"] (http://dictionary.reverso.net/english-cobuild/to%20substitute%20a%20for%20b) == "बी के साथ विकल्प ए" = = (ए) "दूसरे के कार्य को स्थानांतरित करता है या करता है" (बी)। क्या आप अपने उपयोग के लिए कोई संदर्भ दे सकते हैं? – Fulproof

1

एक समस्या यह है कि आप एक से अधिक थ्रेड से FinishedProxies.Add समवर्ती कॉल कर रहे है। यह एक समस्या का कारण बनने जा रहा है क्योंकि List<T> थ्रेड-सुरक्षित नहीं है। आपको इसे लॉक या कुछ अन्य सिंक्रनाइज़ेशन आदिम से बचाने की आवश्यकता होगी, या एक समवर्ती संग्रह का उपयोग करें।

चाहे यूआई लॉकअप का कारण बनता है, मुझे नहीं पता। अधिक जानकारी के बिना, यह कहना मुश्किल है। यदि proxies सूची बहुत लंबी है और checkProxy निष्पादित करने में अधिक समय नहीं लेता है, तो आपके कार्य सभी Invoke कॉल के पीछे कतारबद्ध होंगे। यह लंबित यूआई अपडेट का पूरा समूह बनने जा रहा है। इससे UI को लॉक कर दिया जाएगा क्योंकि यूआई थ्रेड उन कतारबद्ध अनुरोधों को सर्विस करने में व्यस्त है।

+0

क्या आप सूची थ्रेड-सुरक्षित बनाने के तरीके के बारे में मुझे और बता सकते हैं? –

+0

इसके अलावा, मैं परीक्षण चलाने के लिए प्रत्येक बार लगभग 10 प्रॉक्सी लोड करता हूं इसलिए यह बहुत अधिक नहीं है; मैंने समानांतर के बाद एक पंक्ति जोड़ा। पहले से ही 'चेकर पूरा करने के लिए लेबल बॉक्स को बदलता है!' और जब मैं बॉक्स को अद्यतन करने से पहले सभी प्रक्रियाओं को तब तक दबाता हूं जब तक कि सभी प्रक्रियाएं बॉक्स को अपडेट करने से पहले नहीं की जाती हैं, इसलिए यह हां जैसा है कि वे सभी एक साथ चलते हैं, लेकिन ऐसा लगता है जैसे वे एक ही थ्रेड में एक साथ चलते हैं यदि यह कोई समझ में आता है, क्योंकि बस कर रहा है एक ही यूई धागे से httpwebrequest यह ठीक उसी तरह लटका होगा। –

2

यदि कोई उत्सुक है, तो मैंने इसे समझ लिया लेकिन मुझे यकीन नहीं है कि यह अच्छा प्रोग्रामिंग है या इस मुद्दे से निपटने का कोई तरीका है।

मैं बहुत की तरह एक नया धागा बनाया:

Thread t = new Thread(do_checks); 
t.Start(); 

और do_checks के अंदर समानांतर सामान के दूर सब डाल()।

ठीक करने के लिए लगता है।

1

मुझे लगता है कि आपके कोड-बेस में ऐसा हो रहा है।

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

समानांतर का उपयोग करना। Foreach लूप: एक बार जब आप Paralle.Foreach लूप का आह्वान करते हैं, तो फ्रेमवर्क थ्रेडपूल थ्रेड का उपयोग करता है। थ्रेडपूल धागे को यादृच्छिक रूप से चुना जाता है और निष्पादन कोड को चयनित धागे की पहचान पर कभी भी कोई धारणा नहीं लेनी चाहिए। मूल कोड में यह बहुत संभव है कि प्रेषक धागा समानांतर के माध्यम से आक्रमण किया जाता है। Foreach loop उस थ्रेड को समझने में सक्षम नहीं है जो इसके साथ जुड़ा हुआ है। जब आप स्पष्ट धागे का उपयोग करते हैं, तो यह ठीक काम करता है क्योंकि स्पष्ट धागे की अपनी पहचान होती है जिसे निष्पादन कोड द्वारा भरोसा किया जा सकता है।

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

6

समांतर बयानों का उपयोग करते समय यूआई थ्रेड को लिखने में सक्षम नहीं होने की समस्याओं को रोकने के लिए एक अच्छा तरीका है कार्य फैक्ट्री और प्रतिनिधियों का उपयोग करना, निम्नलिखित कोड देखें, मैं इसे फाइलों की एक श्रृंखला पर फिर से चलाने के लिए उपयोग करता हूं एक निर्देशिका है, और एक समानांतर foreach पाश में उन्हें प्रोसेसर, के बाद प्रत्येक फ़ाइल संसाधित किया जाता है यूआई धागा संकेत और अद्यतन किया जाता है:

var files = GetFiles(directoryToScan); 

tokenSource = new CancellationTokenSource(); 
CancellationToken ct = tokenSource.Token; 

Task task = Task.Factory.StartNew(delegate 
{ 
    // Were we already canceled? 
    ct.ThrowIfCancellationRequested(); 

    Parallel.ForEach(files, currentFile => 
    { 
     // Poll on this property if you have to do 
     // other cleanup before throwing. 
     if (ct.IsCancellationRequested) 
     { 
      // Clean up here, then... 
      ct.ThrowIfCancellationRequested(); 
     } 

     ProcessFile(directoryToScan, currentFile, directoryToOutput); 

     // Update calling thread's UI 
     BeginInvoke((Action)(() => 
     { 
      WriteProgress(currentFile); 
     })); 
    }); 
}, tokenSource.Token); // Pass same token to StartNew. 

task.ContinueWith((t) => 
     BeginInvoke((Action)(() => 
     { 
      SignalCompletion(sw); 
     })) 
); 

और तरीकों कि कर वास्तविक यूआई परिवर्तन:

void WriteProgress(string fileName) 
{ 
    progressBar.Visible = true; 
    lblResizeProgressAmount.Visible = true; 
    lblResizeProgress.Visible = true; 

    progressBar.Value += 1; 
    Interlocked.Increment(ref counter); 
    lblResizeProgressAmount.Text = counter.ToString(); 

    ListViewItem lvi = new ListViewItem(fileName); 
    listView1.Items.Add(lvi); 
    listView1.FullRowSelect = true; 
} 

private void SignalCompletion(Stopwatch sw) 
{ 
    sw.Stop(); 

    if (tokenSource.IsCancellationRequested) 
    { 
     InitializeFields(); 
     lblFinished.Visible = true; 
     lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString()); 
    } 
    else 
    { 
     lblFinished.Visible = true; 
     if (counter > 0) 
     { 
      lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString()); 
     } 
     else 
     { 
      lblFinished.Text = "Nothing to resize"; 
     } 
    } 
} 

आशा इससे मदद मिलती है!

+0

आपको UI थ्रेड पर 'BeginInvoke' का उपयोग करके एक और प्रदर्शन बढ़ावा मिल सकता है, तो आपको अपडेट होने के दौरान प्रतीक्षा करने की आवश्यकता नहीं है, जैसा कि आप वर्तमान में' Invoke' का उपयोग करते समय करते हैं। बेशक, इसे 'WriteProgress' के अंदर ताले की आवश्यकता हो सकती है ... –

+0

वर्तमान में यूआई थ्रेड लॉक नहीं किया जा रहा है, यह पूरी तरह उत्तरदायी रहता है, इसलिए मुझे यकीन नहीं है कि यह कैसे मदद कर सकता है? लेकिन मैं इसे अंतर देखने की कोशिश कर रहा हूं, वस्तुओं को लॉक करना मेरे परिदृश्य में कोई समस्या नहीं है। – StevenVL

+0

लॉक के बारे में मेरी टिप्पणी को अनदेखा करें - मैं 'BeginInvoke' चलाने वाले एकाधिक धागे के बारे में सोच रहा था, लेकिन चूंकि वे सभी को यूआई थ्रेड पर बुलाया जा रहा है, इसलिए कोई पुन: प्रवेश नहीं हो सकता है। मैं जो कह रहा था वह है कि आपके 'समांतर' फोरेच 'में प्रत्येक थ्रेड को' Invoke' को पूरा करने के लिए इंतजार करना है, जो चीजों को धीमा कर देगा। 'BeginInvoke' के साथ, यूआई अपडेट यूआई थ्रेड पर कतारबद्ध होंगे और असीमित रूप से चलेंगे। –

0

आप बटन की तरह जीयूआई नियंत्रण में समानांतर foreach उपयोग करने के लिए क्लिक करें आदि तो तरह

private void start_Click(object sender, EventArgs e) 
     { 
       await Task.Factory.StartNew(() => 
        Parallel.ForEach(YourArrayList, (ArraySingleValue) => 
        { 

       Console.WriteLine("your background process code goes here for:"+ArraySingleValue); 
        }) 
        ); 
    }//func end 

Task.Factory.StartNew में समानांतर foreach डाल यह फ्रीज का समाधान हो जाएगा/फंस गए हैं या लटका मुद्दा