在 for 循环中重用 backgroundworker

Reuse backgroundworker in a for loop

我想重复使用 backgroudworker 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 的建议。还是一样。

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

第一个添加的处理程序对应一个唯一的lambda 表达式。当您取消订阅时,您是在一个全新的 lambda 表达式上进行。因此,第一个处理程序永远不会被删除,并且每个 运行.

都会添加一个新的处理程序

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

没有真正的理由尝试重新使用后台工作程序。创建一个根本不昂贵,并且您通过尝试重新使用相同的东西在这里没有任何收获。

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

此外,您正试图在 UI 线程中等待 worker 完成。你不应该这样做。这与整个异步模型背道而驰。

如果你想使用 BGW,你应该在每次完成前一个 worker 时创建并启动一个全新的 worker(如果你还没有完成的话)。您还可以通过使用 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();
}