1

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

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

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

任何想法将不胜感激。

艾略特

4

4 回答 4

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
     }
 }
于 2012-05-22T23:01:21.790 回答
3

一般来说,有三种方法可以在线程之间进行工作拆分。

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

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

While not done:
  Dequeue a document
  Process document

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

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

希望这可以帮助。

于 2012-05-22T23:09:06.387 回答
2

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

于 2012-05-22T23:01:04.833 回答
2

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

于 2012-05-22T23:01:52.587 回答