监视Parallel.ForEach中的进度

时间:2011-03-24 06:08:07

标签: c# multithreading progress-bar parallel-processing

试图监视Parallel.ForEach循环的进度我已经尝试了this question中提出的建议,但不幸的是我仍然无法完成我想要的。

基本上我尝试实现建议(使用计时器)时遇到的第一个问题是Parallel.ForEach方法是一个阻塞调用,因此没有发生timer-tick回调。

所以我尝试将Parallel.ForEach循环放在后台工作线程中。这实际上允许timer-tick事件发生,但我的计数器值永远不会更新,直到ForEach操作完成。

以下是代码的基本概念(使用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;
}

我缺少什么?

3 个答案:

答案 0 :(得分:4)

我打算说,计时员和背景工作者的筑巢让你感到悲伤。

如果可能,我建议你不要再使用Reactive Extensions for .NET (Rx)

如果你这样做,这就是你的代码:

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();

我使用了一些虚拟代码进行了测试,它工作得很好,如果你足够勇敢,你应该能够毫不费力地运行它。 : - )

答案 1 :(得分:1)

虽然我很欣赏Enigmativity在经过一些搜索后发布的解决方案,但我发现了我认为解决这个问题的正确实现。一个不需要任何其他框架来实现的。

全面了解please see this article.

答案 2 :(得分:0)

如果您在主线程中使用普通计时器并通过ConcurrentDictionary传递信息怎么办?