Java 处理文档队列时在线程之间分配工作的最佳方法

Java 处理文档队列时在线程之间分配工作的最佳方法,java,multithreading,Java,Multithreading,我们有一个处理文档队列(基本上是输入目录中的所有文档)的应用程序。文件一个接一个地读入,然后进行处理。应用程序显然是线程的候选对象,因为处理一个文档的结果与处理任何其他文档的结果完全独立。我的问题是如何分配工作 分割工作的一个明显方法是计算队列中的文档数量,除以可用处理器的数量,并相应地分割工作(例如,队列有100个文档,我有4个可用处理器,我创建4个线程,并从队列向每个线程提供25个文档) 然而,一位同事建议,我可以为队列中的每个文档生成一个线程,并让java JVM对其进行排序。我不明白这是

我们有一个处理文档队列(基本上是输入目录中的所有文档)的应用程序。文件一个接一个地读入,然后进行处理。应用程序显然是线程的候选对象,因为处理一个文档的结果与处理任何其他文档的结果完全独立。我的问题是如何分配工作

分割工作的一个明显方法是计算队列中的文档数量,除以可用处理器的数量,并相应地分割工作(例如,队列有100个文档,我有4个可用处理器,我创建4个线程,并从队列向每个线程提供25个文档)

然而,一位同事建议,我可以为队列中的每个文档生成一个线程,并让java JVM对其进行排序。我不明白这是怎么回事。我确实知道第二种方法会产生更干净的代码,但它是否与第一种方法一样高效(甚至更高效)

如有任何想法,将不胜感激


Elliott

不要为每个文档生成线程,而是在线程池中安排可运行任务,该线程池的线程数与处理器的线程数相同。

不要为每个文档生成线程,而是在线程池中安排可运行任务,该线程池的线程数与处理器的线程数相同

我们有一个处理文档队列的应用程序。。。如何分配工作

您应该使用优秀的
ExecutorService
类。像下面这样的方法可以奏效。您可以将每个文件提交到线程池,并由10个工作线程处理它们

 // create a pool with 10 threads
 ExecutorService threadPool = Executors.newFixedThreadPool(10);
 for (String file : files) {
     threadPool.submit(new MyFileProcessor(file));
 }
 // shutdown the pool once you've submitted your last job
 threadPool.shutdown();
 ...
 public class MyFileProcessor implements Runnable {
     private String file;
     public MyFileProcessor(String file) {
        this.file = file;
     }
     public run() {
        // process the file
     }
 }
我们有一个处理文档队列的应用程序。。。如何分配工作

您应该使用优秀的
ExecutorService
类。像下面这样的方法可以奏效。您可以将每个文件提交到线程池,并由10个工作线程处理它们

 // create a pool with 10 threads
 ExecutorService threadPool = Executors.newFixedThreadPool(10);
 for (String file : files) {
     threadPool.submit(new MyFileProcessor(file));
 }
 // shutdown the pool once you've submitted your last job
 threadPool.shutdown();
 ...
 public class MyFileProcessor implements Runnable {
     private String file;
     public MyFileProcessor(String file) {
        this.file = file;
     }
     public run() {
        // process the file
     }
 }

您不需要以这种方式拆分文档。只需创建固定数量的工作线程(即使用
执行器创建两个工作线程。newFixedThreadPool(2)
),每个线程一次只能处理一个文档。当它处理完一个文档后,会从共享列表中获取一个新文档。

您不需要这样拆分文档。只需创建固定数量的工作线程(即使用
执行器创建两个工作线程。newFixedThreadPool(2)
),每个线程一次只能处理一个文档。处理完一个文档后,它会从共享列表中获取一个新文档。

通常,有三种方法可以在线程之间进行工作拆分

首先,静态分区。这是静态地计算和划分文档的地方(即,不考虑处理每个文档需要多长时间)。这种方法非常有效(并且通常易于编码),但是,如果文档处理时间不同,则可能会导致性能低下。一个线程可能会意外地被所有长文档卡住,这意味着它将运行最长时间,并且您的并行性将受到限制

第二,动态分区(您没有提到这一点)。生成固定数量的线程,并让每个线程在一个简单循环中工作:

While not done:
  Dequeue a document
  Process document
这样可以避免负载不平衡。在处理每个文档之后,您会产生访问队列的开销,但只要每个文档的处理时间远远长于队列访问时间,这一开销就可以忽略不计(因此,我认为您应该这样做)

第三,让JVM完成您的工作调度。这是您跨越N个线程并让它们进行斗争的地方。这种方法相当简单,但它的缺点是,您将严重依赖于JVM线程调度,如果JVM在这方面做得不好,它可能会非常慢。有太多的线程相互鞭打可能会非常慢。我希望JVM比这更好,所以这可能值得一试


希望这有帮助

通常,有三种方法可以在线程之间进行工作拆分

首先,静态分区。这是静态地计算和划分文档的地方(即,不考虑处理每个文档需要多长时间)。这种方法非常有效(并且通常易于编码),但是,如果文档处理时间不同,则可能会导致性能低下。一个线程可能会意外地被所有长文档卡住,这意味着它将运行最长时间,并且您的并行性将受到限制

第二,动态分区(您没有提到这一点)。生成固定数量的线程,并让每个线程在一个简单循环中工作:

While not done:
  Dequeue a document
  Process document
这样可以避免负载不平衡。在处理每个文档之后,您会产生访问队列的开销,但只要每个文档的处理时间远远长于队列访问时间,这一开销就可以忽略不计(因此,我认为您应该这样做)

第三,让JVM完成您的工作调度。这是您跨越N个线程并让它们进行斗争的地方。这种方法相当简单,但它的缺点是,您将严重依赖于JVM线程调度,如果JVM在这方面做得不好,它可能会非常慢。有太多的线程相互鞭打可能会非常慢。我希望JVM比这更好,所以这可能值得一试


希望这有帮助

多谢各位。正是我需要的。谢谢。正是我需要的。