在for循环中重用backgroundworker

时间:2015-01-30 14:38:54

标签: c# backgroundworker

我想重复使用一次背景技术MAX_RUNS次。我使用以下代码:

BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
for (int run =1; run <=MAX_RUNS; run++)
{
        backgroundWorker1.DoWork += (s, args) =>
        {
           // Time consuming DLL call
        };
        backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        backgroundWorker1.RunWorkerAsync();
        while (backgroundWorker1.IsBusy)
        {
            backgroundWorker1.ReportProgress(time, "TIME");
            Application.DoEvents();
        }
        backgroundWorker1.DoWork -= (s, args) =>
        {
           // Time consuming DLL call
        };
        backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;
        backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;
}

它可以工作,但唯一的问题是后台工作程序运行2 * MAX_RUNS次。这种奇怪行为可能是什么原因?

EDIT1:在RunWorkerCompleted之后移动RunWorkerAsync。仍然是同样的问题。

EDIT2:添加了@Crono的建议。还是一样。

2 个答案:

答案 0 :(得分:1)

尝试重新使用后台工作程序没有真正的原因。创建一个并不昂贵,而且你试图重复使用同一个东西并没有在这里获得任何东西。

至于为什么你的方法被解雇了很多次,你没有正确地取消订阅事件。您订阅的lambda是一个委托,它具有与您取消订阅的委托不同的对象实例和方法指针;由于你未能取消订阅这些事件,它会在第一次运行时触发1个事件,在第二次运行时触发2个事件,在第三次运行时触发3个等等,以便n*(n+1)/2总方法被触发。

此外,您正试图在UI线程中等待工作人员完成。你不应该这样做。这与整个异步模型相反。

如果你想使用BGW,你应该在每次完成前一个工作时创建并启动一个全新的工人(如果你没有完成)。您也可以使用TPL来大大简化程序:

public async void Foo(IProgress<T> progress)
{
    for(int i = 0; i < MAX_RUNS; i++)
    {
        await Task.Run(() => TimeConsumingMethodCall());
        WhateverYoureDoingWhenEachWorkerCompletes();
        progress.Report(time);
    }
    UpdateUIWithFinalResults();
}

答案 1 :(得分:0)

我认为您没有正确添加/删除DoWork处理程序。

第一个添加的处理程序对应于唯一的lambda表达式。当你取消订阅时,你正在使用一个全新的lambda表达式。因此,第一个处理程序永远不会被删除,并且每次运行都会添加一个新处理程序。

尝试用实际方法替换lambda表达式。它可能会解决您的问题。即使它并不是你真正应该做的事情。