我们有一个处理文档队列的应用程序(基本上是在输入目录中找到的所有文档)。逐个读取文档,然后进行处理。该应用程序显然是线程的候选者,因为处理一个文档的结果完全独立于处理任何其他文档的结果。我的问题是如何划分工作。
分解工作的一个显而易见的方法是计算队列中的文档数量,除以可用处理器的数量并相应地拆分工作(例如,队列有100个文档,我有4个可用的处理器,我创建4个线程并从队列中将25个文档提供给每个线程)。
但是,同事建议我可以为队列中的每个文档生成一个线程,让java JVM对其进行排序。我不明白这是如何工作的。我确实得到第二种方法可以产生更干净的代码,但是它与第一种方法一样有效(甚至更有效)吗?
任何想法都会受到赞赏。
埃利奥特
答案 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比这更好,所以这可能值得一试。
希望这会有所帮助。