我有一个后台工作程序,需要根据选中的复选框的数量多次调用 - 我已经写了这个来获取复选框值并将它们放入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的下一次迭代时它会崩溃说工作者正忙 - 即使工作者已经返回它的WorkerCompleted状态。
如何在循环的下一次迭代之前确保线程已关闭?
注意:我对包含!backgroundWorker1.IsBusy()
的后台工作者有条件,但这(显然)只是在没有执行的情况下跳过剩余的迭代。
答案 0 :(得分:1)
如果要按顺序处理每个项目,则没有理由为每个任务使用单独的后台工作程序。因此,将foreach循环移动到DoWork方法会更好。但是如果你想在并行处理所有项目,你需要为每个项目创建一个后台工作者。
答案 1 :(得分:1)
来自MSDN:
如果后台操作已在运行,则再次调用RunWorkerAsync将引发InvalidOperationException。
因此,您无法使用BackgroundWorker
来维护队列任务(并且您可以按顺序推送所有任务,而无需等待之前的任务完成)。您有不同的解决方案,例如,如果您想继续使用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.Task
或ThreadPool
(直接或间接,大多数并行操作将排队到池中)。
答案 2 :(得分:1)
您的foreach-code将立即触发所有元素的工作。这就是你得到例外的原因。
如果要按顺序启动工作程序,则只能在启动时调用RunWorkerAsync,然后为每个WorkerComplete事件调用。但是为什么不在工作代码中进行处理?
答案 3 :(得分:1)
BackgroundWorker真的很忙,因为第一次调用backgroundWorker1.RunWorkerAsync(rep);
时,它不等待任何事情,然后立即调用第二个,第三个......调用。
你应该在每次调用时创建BackgroundWorker,然后就可以了。
答案 4 :(得分: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);
});