0

我正在从日志文件中提取与模式匹配的行。因此,我将每个日志文件分配给一个 Runnable 对象,该对象将找到的模式行写入结果文件。(同步良好的编写器方法)

正在讨论的重要片段:

ExecutorService executor = Executors.newFixedThreadPool(NUM_THREAD);


for (File eachLogFile : hundredsOfLogFilesArrayObject) {
executor.execute(new RunnableSlavePatternMatcher(eachLogFile));
}

重要标准:

日志文件的数量可能很少,比如 20 个,或者对于某些用户来说,日志文件的数量可能超过 1000 个。我在 Excel 表中记录了一系列测试,我真的很担心标记为 RED 的结果。

1.我假设如果创建的线程数等于要处理的文件数,那么处理时间会更少,与线程数小于要处理的文件数的情况相比不会发生。(如果我的理解有误请指教)

结果 :

结果

  1. 我想为 NUM_THREAD 确定一个值,该值对于更少的文件以及 1000 个文件是有效的

建议我回答问题 1 和 2

谢谢 !钱德鲁

4

5 回答 5

3

您刚刚发现您的程序不受 CPU 限制,而是(可能)受 IO 限制

这意味着超过 10 个线程,操作系统无法跟上所有需要其数据的线程的请求读取,并且更多线程一次等待下一个数据块

还因为编写输出在所有线程之间同步,这甚至可能是程序中最大的瓶颈,(生产者-消费者解决方案可能是这里的答案,以最大限度地减少线程等待输出的时间)

最佳线程数取决于您读取文件的速度(读取速度越快,线程越有用),

于 2013-09-20T14:52:59.023 回答
2

看来 2 个线程足以使用您所有的处理能力。很可能您有两个内核和超线程。

我的是英特尔 i5 2.4GHz 4CPU 8GB 内存。这个细节有用吗?

根据型号,它有 2 个内核和超线程。

我假设如果创建的线程数等于要处理的文件数,那么处理时间会更少,

这将最大化开销,但不会给你比你已经拥有的更多的核心。

于 2013-09-20T14:42:27.880 回答
1

一个问题是 I/O 不能很好地并行化,特别是如果你有一个非 SSD,因为顺序读取(当一个线程读取文件时会发生什么)比随机读取(当读取头必须跳来跳去时)快得多在多个线程读取的不同文件之间)。我猜您可以通过从将作业发送到执行程序的线程中读取文件来加速程序:

for (File file : hundredsOfLogFilesArrayObject) {
    byte[] fileContents = readContentsOfFile(file);
    executor.execute(new RunnableSlavePatternMatcher(fileContents));
}

至于最佳线程数,这取决于。

如果您的应用程序是 I/O 绑定的(如果您没有对内容进行非常繁重的处理,这很有可能),一个可以在原始线程读取下一个文件时处理文件内容的工作线程可能就足够了。

如果你受 CPU 限制,你可能不想要比你拥有的内核更多的线程:

ExecutorService executor = Executors.newFixedThreadPool(
    Runtime.getRuntime().availableProcessors());

虽然,如果您的线程被挂起很多(等待同步锁或其他东西),您可能会通过更多线程获得更好的结果。或者,如果您正在进行其他占用 CPU 的活动,您可能需要更少的线程。

于 2013-09-20T15:04:40.057 回答
1

并行化时,使用比可用 cpu 内核更多的线程通常会增加总时间。您的系统将花费一些开销时间在一个 cpu 内核上从一个线程切换到另一个线程,而不是让它一个接一个地一次执行任务。

如果您的计算机上有 8 个 cpu 内核,您可能会观察到使用 8/9/10 个线程而不是仅使用 1 个线程的一些改进,而使用 20+ 个线程实际上效率会降低。

于 2013-09-20T14:16:27.213 回答
0

您可以尝试使用缓存线程池。

public static ExecutorService newCachedThreadPool()

创建一个线程池,根据需要创建新线程,但在可用时将重用以前构造的线程。这些池通常会提高执行许多短期异步任务的程序的性能。如果可用,对执行的调用将重用以前构造的线程。

你可以在这里阅读更多

于 2013-09-20T14:17:11.163 回答