2

我有一个后台工作人员,需要根据选中的复选框数量多次调用 - 我已经编写了这个来获取复选框值并将它们放入List.

List repSelected = new List();

这被填充,然后像这样迭代:

foreach (string rep in repSelected)
{
    backgroundWorker1.RunWorkerAsync(rep);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}

异步的 DoWork 代码如下所示:

BackgroundWorker worker = sender as BackgroundWorker;
string rep = e.Argument.ToString();

if (worker.CancellationPending == true)
{
    e.Cancel = true;
}
else
{
    DirectoryExists(rep);
    ProcessRunner(rep); //Rars some large files - expensive
}

然后该进程运行 WorkerComplete,问题是当该进程返回执行 Worker 的下一次迭代时,它会崩溃,说该 Worker 很忙——即使该 Worker 已返回其 WorkerCompleted 状态。

如何确保在循环的下一次迭代之前关闭线程?

注意:我对包含后台工作人员有一个条件,!backgroundWorker1.IsBusy()但这(显然)只是跳过了剩余的迭代而没有执行。

4

5 回答 5

1

如果您想按顺序处理每个项目,则没有理由为每个任务使用单独的后台工作程序。所以最好将 foreach 循环移到 DoWork 方法中。但是如果要并行处理所有项目,则需要为每个项目创建一个后台工作人员。

于 2012-05-17T10:42:07.613 回答
1

来自 MSDN:

如果后台操作已经在运行,再次调用 RunWorkerAsync 将引发 InvalidOperationException。

因此,您不能使用 aBackgroundWorker来维护任务队列(并且您按顺序推送所有任务而无需等待前一个任务完成)。您对此有不同的解决方案,例如,如果您想继续使用,BackgroundWorker您可以这样做:

backgroundWorker1.RunWorkerAsync(repSelected);

然后改变你的DoWork方法如下:

BackgroundWorker worker = sender as BackgroundWorker;

foreach (string rep in (IEnumerable<string>)e.Argument)
{
    if (worker.CancellationPending == true)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        DirectoryExists(rep);
        ProcessRunner(rep); //Rars some large files - expensive
    }
}

作为替代方案,您可以考虑更改执行此任务的方式,例如使用System.Threading.Tasks.TaskThreadPool(直接或间接,大多数并行操作将排队到池中)。

于 2012-05-17T10:43:02.730 回答
1

您的 foreach 代码将立即触发所有元素的工作。这就是你得到异常的原因。

如果要按顺序启动 Worker,只能在启动时调用 RunWorkerAsync 一次,然后为每个 WorkerComplete-event 调用。但是为什么不在工作代码中进行处理 foreach 呢?

于 2012-05-17T10:44:28.097 回答
1

BackgroundWorker 真的很忙,因为当第一次调用 时backgroundWorker1.RunWorkerAsync(rep);,它不等待任何东西,然后立即调用第二个、第三个、... 调用。

您应该在每次调用时创建 BackgroundWorker,然后就可以了。

于 2012-05-17T10:46:40.423 回答
1

你可以使用parallel.foreach 和多个backgroundworkers;

Parallel.ForEach(YourListofStrings,
                 (q) =>
                 {
                     BackgroundWorker worker = new BackgroundWorker();
                     worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                     worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                     worker.RunWorkerAsync(q);
                 });
于 2012-05-17T11:10:18.947 回答