后台工作进程和文件系统观察程序一起工作时出错
本文关键字:工作 一起 出错 程序 文件系统 进程 后台 观察 | 更新日期: 2023-09-27 18:26:26
嗨,我在使用Filesystemwatch&BackgroundWorker进程。
我有一个windows窗体应用程序,它检查文件夹中的新文本文件,处理它们并从中创建xml文件。
我正在使用FSW监控文件夹中的新txt文件,该应用程序运行良好,但当文件夹接收到大量文件(比如1000个)时,该应用会冻结,因为它正在处理所有文件。
我突然想到添加一个后台工作程序,所以FSW每次创建新文件时都会调用它,这样我们就可以在后台处理文件,而不会冻结UI。
这个想法没有奏效,因为对于创建的每个文件,我都会尝试调用RunWorkerSync()方法,所以如果它忙于处理一个文件,而我试图处理一个新文件,它会抛出以下错误:
"此BackgroundWorker当前正忙,无法同时运行多个任务。"
所以我试着循环这个方法一段时间,直到它可用,但是,抛出了无限的异常。这是我的代码的简化版本:
private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
{
readFile();
}
private void readFile()
{
while (backgroundWorker1.IsBusy)
{
readFile();
}
backgroundWorker1.RunWorkerAsync(idx);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int i = (int)e.Argument;
i += 1;
e.Result = i;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = "Processing...";
this.Refresh();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label1.Text = "Completed...";
this.Refresh();
idx = (int)e.Result;
}
抛出的异常显示"WindowsFormsApplication2.exe中发生类型为"System.StackOverflowException"的未处理异常,请确保没有无限循环或递归"
我当然可以删除FSW,但我想知道是否有办法让它们协同工作,有什么想法吗?
您遇到的是一个典型的生产者/消费者问题。
用System.Collections.Concurrent.ConcurrentQueue<string>
求解。
- 在FSW事件中,将文件名添加到队列中
- 启动1或2个BackgroundWorkers来处理队列
这是匆忙溢出堆栈的代码:
private void readFile()
{
while (backgroundWorker1.IsBusy)
{
readFile(); // the recursive call, will fail quickly
}
backgroundWorker1.RunWorkerAsync(idx);
}
这不仅会导致SO异常,还会阻塞主线程
您需要一种更好的等待方式,ConcurrentQueue为您提供了这一点。
实例化新的BackgroundWorkers就可以了,就像Henk上面的解决方案一样。
或者,只需使用ThreadPool
,就可以在不过多更改代码的情况下完成此操作。
private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
{
ThreadPool.QueueUserWorkItem(o => readFile(e));
}
public void readFile(System.IO.FileSystemEventArgs e)
{
this.BeginInvoke(new MethodInvoker(() =>
{
label1.Text = "Processing...";
this.Refresh(); //you shouldn't need this
}));
//your long running read/processing... doing something event args
this.BeginInvoke(new MethodInvoker(() =>
{
label1.Text = "Completed...";
this.Refresh();
idx = (int) e.Result;
}));
}
为什么不在readFile中实例化一个新的BackgroundWorker而不是重用?