我在这里看到的问题是,您旋转了如此多的线程,以至于您只需管理所有排队的线程,即使从技术上讲它们不会尝试同时运行,您也会使机器资源过载。他们将占用 RAM,并且在没有 RAM 的情况下,将使用 SWAP 空间——这将使机器在非荣耀的火焰中崩溃。
我会使用一个队列(天蓝色队列,msmq,Systems.Collections.Queue)来排队所有对象,使用有限数量的线程,这些线程将使用后台链接中描述的异步方法处理文件,然后线程完成执行检查队列中的下一项并处理该项。我的建议是使用非内存队列——我将在下面解释。主要好处是节省内存,这样您的软件就不会因为队列太大而崩溃或变慢。
Parallel.ForEach 等可以节省大量时间,但在处理大量项目时确实会破坏机器的性能 - 如果机器出现故障,那么除非您在某处有检查点,否则您将无法从中恢复。使用持久队列不仅可以让您正确管理机器资源,还可以正确管理您在流程中的位置。
然后,您可以使用 MSMQ 之类的持久队列或如果在云中使用 Azure 队列,在多台机器上进行扩展。如果您使用检查 azure 队列有多大的服务,您甚至可以不时启动实例以减少负载,然后终止额外的实例。
这是我要实现的场景:
使用标准 ThreadPool 大小 当您检测到新文件/批处理时 - 提交到队列 每次在队列中插入新项目时触发事件(如果是内存队列) 让进程检查队列(如果是持久队列) 如果新项目在队列中,首先检查 ThreadPool 中是否有空间 如果没有则忽略(使用 PEEK 方法,因此您不会删除该项目) - 如果有空间,则将工作线程添加到 ThreadPool 进程线程(在 ThreadPool 下运行)应该执行,然后检查队列中是否有另一个项目 - 如果没有 - 线程死亡,这很好
使用这种方法,您可以在 1 台机器或 50,000 台机器上运行它——只要您为超过 1 台机器使用持久队列,您就不会遇到任何问题。当然,如果您使用 Azure 队列,请确保您对重复项目进行了正确的测试,因为您可能会收到已被提供给另一台计算机的排队项目。
这是一种简单的方法,可扩展,并且如果使用持久队列(甚至是文件系统)可以从故障中恢复。但是,它不会通过强制它管理包含 100 万个以上项目的 ThreadPool 来滥用资源来使机器过载。
希望这可以帮助