我的应用程序非常适合处理位于我服务器上的目录中的文件。这个过程是:
1) check for files in a directory
2) queue a user work item to handle each file in the background
3) wait until all workers have completed
4) goto 1
这很好用,我从不担心同一文件被处理两次或多个线程被生成同一个文件。但是,如果有一个文件需要很长时间才能处理,那么步骤#3会挂起该文件并保留所有其他处理。
所以我的问题是,为我需要处理的每个文件生成一个线程的正确范例是什么,而如果一个文件需要太长时间则不阻塞?我考虑过FileSystemWatcher,但文件可能无法立即读取,这就是为什么我不断查看所有文件并为每个文件生成一个进程(如果文件被锁定将立即退出)。
我应该删除第3步并维护我已经处理过的文件列表吗?这似乎很混乱,随着时间的推移,列表会变得非常大,所以我怀疑这是一个更优雅的解决方案。
答案 0 :(得分:6)
我建议您维护一份当前正在处理的文件列表。线程完成后,让线程从此列表中删除。查找新文件时,请排除当前运行列表中的文件。
答案 1 :(得分:3)
在启动线程之前将文件移动到处理目录。然后你可以发射并忘记线程,任何管理员都可以一目了然地看到发生了什么。
答案 2 :(得分:3)
每个要处理的项目产生一个线程几乎从来都不是好方法。在您的情况下,当文件数量超过几百个单个每个文件的线程将使应用程序性能非常糟糕,并且32位进程将开始耗尽地址空间。
Dark Falcon的列表解决方案非常简单,与您的算法相匹配。我实际上会使用队列(类似于ConcurrentQueue - http://msdn.microsoft.com/en-us/library/dd267265.aspx)将项目放在一边处理(即基于文件观察者的定期扫描),并选择要由另一侧的一个或多个线程处理的项目。您通常需要较少数量的线程(即,CPU密集型负载的CPU数量为1-2x)。
还可以考虑使用任务并行库(如Parallel.ForEach - http://msdn.microsoft.com/en-us/library/dd989744.aspx)来处理多个线程。
要最小化要处理的文件数量,我会保留已经处理的项目的持久性(即磁盘文件)列表 - 文件路径+上次修改日期(除非您可以从其他来源获取此信息)。
答案 3 :(得分:1)
我的两个主要问题是:
根据你的答案,我可能会使用以下生产者 - 消费者算法:
我觉得这是非阻塞,低CPU使用行为的良好组合。但要衡量你的前后结果。我建议使用ThreadPool并尝试阻止线程阻塞(即,尝试通过执行类似Thread.Sleep之类的操作来确保线程重用)
注意: