【问题标题】:Clarification on Thread performance processing 1000's of log files关于线程性能处理 1000 个日志文件的说明
【发布时间】:2013-09-20 14:07:23
【问题描述】:

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

正在讨论的重要sn-p:

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

谢谢! 钱德鲁

【问题讨论】:

  • 除了第一行,你所有的数字看起来都差不多。我没有发现任何重大问题。
  • @MarkoTopolnik 也许是因为初始属性文件变量初始化。您能否建议一个适合任何情况的 NUM_THREAD 值(无论是 10 个文件还是 1000 个文件?将 500 作为值是个好主意)
  • 最佳数量高度依赖于上下文:您拥有多少内核,每个线程花费多少等待 I/O 操作,一个文件的读取速度因读取另一个文件而减慢了多少文件(磁盘寻道时间)等

标签: java multithreading performance executorservice


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    这将使开销最大化,但不会为您提供比现有更多的内核。

    【讨论】:

    • 我尝试使用 2 个线程处理 40 个文件,总时间 = 170 秒
      我使用 20 个线程处理 40 个文件,总时间 = 145 秒,节省了 25 秒
      我现在对设置适用于所有文件数量的 NUM_THREAD 的值感到非常困惑。 10 到 1000 的
    • 无需混淆。就像我说的,如果你使用超过 2 个线程,你会得到越来越多的开销,而且速度会变慢。
    【解决方案3】:

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

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

    【讨论】:

    • OP 正在使用阻塞 I/O,这通常意味着等待阻塞调用。天平没那么简单。
    • 我知道,但似乎在这种情况下,它花费了相当多的时间来处理数据。否则使用 1 个或多个线程几乎保持不变。
    • 我的是 Intel i5 2.4GHz 4CPU
      8GB Ram 。这个细节有用吗?
    【解决方案4】:

    一个问题是 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 的活动,您可能需要更少的线程。

    【讨论】:

      【解决方案5】:

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

      public static ExecutorService newCachedThreadPool()
      

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

      您可以阅读更多here

      【讨论】:

      • 这可能会创建 ton 的线程,无论最佳线程数是多少。
      猜你喜欢
      • 2021-10-24
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-27
      相关资源
      最近更新 更多