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

时间:2012-05-22 22:57:03

标签: java multithreading

我们有一个处理文档队列的应用程序(基本上是在输入目录中找到的所有文档)。逐个读取文档,然后进行处理。该应用程序显然是线程的候选者,因为处理一个文档的结果完全独立于处理任何其他文档的结果。我的问题是如何划分工作。

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

但是,同事建议我可以为队列中的每个文档生成一个线程,让java JVM对其进行排序。我不明白这是如何工作的。我确实得到第二种方法可以产生更干净的代码,但是它与第一种方法一样有效(甚至更有效)吗?

任何想法都会受到赞赏。

埃利奥特

4 个答案:

答案 0 :(得分:7)

  

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

您应该使用优秀的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
     }
 }

答案 1 :(得分:2)

不要为每个文档生成一个线程,而是在一个Threadpool上安排一个Runnable任务,该任务具有例如与处理器一样多的线程。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

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

其次,动态分区(你没有提到这一点)。产生固定数量的线程,让每个线程在一个简单的循环中工作:

While not done:
  Dequeue a document
  Process document

通过这种方式可以避免负载不平衡。在处理每个文档之后,您会产生访问队列的开销,但只要每个文档的处理时间远远长于队列访问(因此,我认为您应该这样),这将是可以忽略不计的。

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

希望这会有所帮助。