Monitoring Progress in Parallel.ForEach
Solution 1
Although I do appreciate the solution posted by Enigmativity after some searching I have found what I consider the correct implementation for solving this problem. One that does not require any other frameworks to implement.
For a full overview please see this article.
Solution 2
I'm going to take a stab at saying the nesting of timers and background workers is causing you grief.
If possible, I suggest you avoid then in favour of using the Reactive Extensions for .NET (Rx).
This 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 should be able to get this running without to much difficulty. :-)
Maxim Gershkovich
Developer with experience in. ASP.NET Azure Point of sale software C# VB.NET .NET Framework Sharepoint MVC Microsoft Kinect for Windows 1.8 & 2
Updated on June 04, 2022Comments
-
Maxim Gershkovich almost 2 years
Attempting to monitor progress of a Parallel.ForEach loop I have tried the suggestion put forward in this question but unfortunately I have still been unable to accomplish what I wanted.
Basically the first problem I ran into when I attempted the implementation suggested (using a timer) was that the Parallel.ForEach method is a blocking call and hence the timer-tick callback was not occurring.
So I tried putting the Parallel.ForEach loop inside of a background worker thread. Which did infact allow for the timer-tick event to occur but my counter value is never updated until the ForEach operation is complete.
Here is the basic idea of the code (with the backgroundworker).
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?