Monitoring progress in Parallel.ForEach

Trying to control the progress of the Parallel.ForEach cycle, I tried the suggestion proposed in this question , but, unfortunately, I still could not fulfill what I wanted.

Basically, the first problem that I encountered when trying to implement the proposed implementation (using a timer) was that the Parallel.ForEach method is a blocking call and therefore the timer callback was not executed.

So I tried to set the Parallel.ForEach loop inside the workflow. As a result of the infanta, a timer event was resolved, but the value of my counter is never updated until the ForEach operation completes.

Here is the main idea of ​​the code (with background).

private StockList _StockListToProcess = null; private static Int64 ItemsProcessed = 0; private System.Windows.Threading.DispatcherTimer _timer = null; private System.ComponentModel.BackgroundWorker _backWorker = null; progressBar1.Minimum = 1; progressBar1.Maximum = this._StockListToProcess.Count; MainWindow.ItemsProcessed = 0; this._timer = new System.Windows.Threading.DispatcherTimer(); this._timer.Interval = TimeSpan.FromMilliseconds(100); this._timer.Tick += timer_Tick; this._timer.Start(); this._backWorker = new System.ComponentModel.BackgroundWorker(); this._backWorker.DoWork += delegate(object o, System.ComponentModel.DoWorkEventArgs args) { Parallel.ForEach(this._StockListToProcess, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (Stock stock) => { MyWebServiceClient serviceClient = new MyWebServiceClient (); MyWebServiceClient.ResponseEnum result = (MyWebServiceClient .ResponseEnum)serviceClient.SetProductPricing(token.LoginName, token.LoginPassword, token.SiteID.ToString(), stock.ProductCode, stock.ProductPrice); System.Threading.Interlocked.Increment(ref MainWindow.ItemsProcessed); }); this._timer.Stop(); }; private void timer_Tick(object sender, EventArgs e) { progressBar1.Value = MainWindow.ItemsProcessed; } 

What am I missing?

+4
source share
3 answers

Although I really appreciate the solution posted by Enigmativity after some searching, I found what I consider to be the correct implementation to solve this problem. One that does not require any other frameworks to implement.

See this article for a full review .

+1
source

I'm going to take a hit by saying that nesting timers and background workers makes you sad.

If possible, I suggest you avoid using Reactive Extensions for.NET (Rx) .

Here is what your code would look like if you did:

 progressBar1.Minimum = 1; progressBar1.Maximum = this._StockListToProcess.Count; var itemsProcessed = 0; var updater = new Subject<Unit>(Scheduler.Dispatcher); updater.Subscribe(u => { itemsProcessed += 1; //Rx serializes "OnNext" calls so this is safe. progressBar1.Value = itemsProcessed; }); Parallel.ForEach(this._StockListToProcess, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (Stock stock) => { MyWebServiceClient serviceClient = new MyWebServiceClient (); MyWebServiceClient.ResponseEnum result = (MyWebServiceClient .ResponseEnum)serviceClient.SetProductPricing(token.LoginName, token.LoginPassword, token.SiteID.ToString(), stock.ProductCode, stock.ProductPrice); updater.OnNext(new Unit()); }); updater.OnCompleted(); 

I did a test using a dummy bit of code, and it worked fine, so if you are brave enough, you can achieve this without much difficulty. :-)

+4
source

What if you use a regular timer in your main thread and pass information through ConcurrentDictionary?

0
source

Source: https://habr.com/ru/post/1345041/


All Articles