【问题标题】:how many threads to run in java?在java中运行多少个线程?
【发布时间】:2012-10-01 18:22:32
【问题描述】:

我有一个绝妙的主意来加快生成 36 个文件所需的时间:使用 36 个线程!不幸的是,如果我用 36 个线程/会话启动一个连接(一个 j2ssh 连接对象),那么一切都会比我一次执行每个线程时滞后得多。
现在,如果我尝试创建 36 个新连接(36 个j2ssh 连接对象),那么每个线程都有一个与服务器的单独连接,要么我出现内存不足异常(不知何故程序仍然运行,并成功结束了它的工作,比我一个接一个地执行一个线程的时间)。

那该怎么办?如何找到我应该使用的最佳线程数? 因为Thread.activeCount() 在开始我的 36 个线程之前是 3?!我正在使用联想笔记本电脑英特尔酷睿 i5。

【问题讨论】:

  • 您是在服务器端还是在 j2ssh 连接的客户端运行工作线程?
  • @Paŭlo Ebermann 在服务器上运行它们,线程 == 向服务器发送 2 个命令
  • 听起来你需要看看你的 JVM 是否内存不足。

标签: java multithreading


【解决方案1】:

您可以使用ExecutorService 将其缩小到更合理的线程数。您可能想要使用接近可用处理器内核数量的东西,例如:

int threads = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(threads);
for (int i = 0; i < 36; i++) {
    service.execute(new Runnable() {
        public void run() {
            // do what you need per file here
        }
    });
}
service.shutdown();

【讨论】:

  • 你看这里完成时间是~30分钟我猜36个操作中的每一个都是一个接一个地创建和执行的,thread1.start;thread1.end;thread2.start;thread2.end.. thread36.end ... 我个人希望至少在 12 分钟内而不是 30 分钟内执行,现在可以提高速度,我设置的线程数(Executors.newFixedThreadPool(threads);)是 4
【解决方案2】:

一个好的做法是生成与处理器中的内核数相等的线程。我通常使用Executors.fixedThreadPool(numOfCores) executor 服务并继续为其提供我的作业队列中的作业,很简单。 :-)

【讨论】:

    【解决方案3】:

    您的 Intel i5 有两个内核;超线程使它们看起来像四个。所以你只能得到四个核心的并行化;你的其余线程是时间切片的。

    假设每个线程 1MB RAM 仅用于创建线程,然后添加每个线程处理文件所需的内存。这将使您了解为什么会出现内存不足错误。您正在处理的文件有多大?您可以看到,如果它们非常大,无法同时将它们放在内存中,您就会遇到问题。

    我假设接收文件的服务器可以接受多个连接,所以尝试这样做是有价值的。

    我会用 1 个线程进行基准测试,然后增加它们,直到我发现性能曲线变平为止。

    【讨论】:

    • 你是对的,服务器可以同时执行至少三个命令(甚至可能是 36 个)。所以我想同时在thread1,2上运行两个命令,然后在主线程上运行第三个命令?!
    【解决方案4】:

    蛮力:增量分析。逐渐增加线程数并检查性能。由于连接数只有 36,应该很容易

    【讨论】:

      【解决方案5】:

      您需要了解,如果您创建 36 个线程,您仍然有一个或两个处理器,并且大部分时间它会在威胁之间切换。

      我会说你稍微增加线程,比如说 6 并查看行为。然后从那里去

      【讨论】:

        【解决方案6】:

        将线程数调整为机器大小的一种方法是使用

        int processors = Runtime.getRuntime().availableProcessors();
        int threads = processors * N; // N could 1, 2 or more depending on what you are doing.
        ExecutorService es = Executors.newFixedThreadPool(threads);
        

        【讨论】:

          【解决方案7】:

          首先你必须找出瓶颈在哪里

          • 如果是SSH连接,通常并行打开多个连接无济于事。如果需要,最好在一个连接上使用多个通道。

          • 如果是磁盘 IO,创建多个写入(或读取)线程只有在它们访问不同磁盘时才有帮助(这种情况很少发生)。但是,当您在一个线程中等待磁盘 IO 时,您可以让另一个线程执行 CPU 绑定的事情。

          • 如果是 CPU,并且您有足够的空闲内核,则更多线程会有所帮助。更重要的是,如果他们不需要访问公共数据。但是,多于内核的线程(+ 一些执行 IO 的线程)仍然无济于事。 (还请注意,您的服务器上通常还有其他进程。)

          【讨论】:

          • 另一个注意事项:在 unix-ish 机器上,htop 是查看 CPU 和内存使用情况的好工具。
          【解决方案8】:

          使用比机器上的内核数更多的线程只会减慢整个过程。它会加速直到你达到这个数字。

          【讨论】:

          • 所以如果我有 4 个内核,我认为最佳速度是当时使用 3 个线程?至少我以这种方式检查了(使用几个命令)时间:Executors.fixedThreadPool(2) -time 6:40min fixedThreadPool(3)-5:28min。 ThreadPool(4)-9:56 分钟更长!线程池(8)-13:13 分钟。我可以使用的最大线程数是 3 ?!
          【解决方案9】:

          请确保创建的线程数不会超过处理单元的数量,否则上下文切换产生的开销可能会超过并发获得的开销。还请记住,您只有 1 个 HDD 和 1 个 HDD 控制器,我怀疑多线程在这里根本不会帮助您。

          【讨论】:

          • 请记住,结果您只有 1 个 HDD 和 1 个 HDD 控制器,我怀疑多线程在这方面对您有帮助。 为什么?如果我可以通过 putty 打开 5 个不同的窗口(到服务器的 5 个连接)并执行 5 个命令组,我应该能够使用 java 做同样的事情?!
          • 不清楚您是否在一个系统上创建 36 个文件,如果您要与单个系统建立 36 个连接,那么驱动器并发可能是一个问题,除非系统正在运行存储系统超出单个 HDD。您必须想象 HDD 是一个单线程实体,一次只能执行一次写入。
          • 您需要了解线程之间的切换不是“免费”的,它需要时间。这只是一点点时间,但是当您将该时间乘以 36 个线程时,这些线程可能每秒多次切换上下文,并且该库可能没有针对多线程进行大量优化,您所花费的时间比您想象的要多得多。穿线不是万能的灵丹妙药,除非你真的了解发生了什么,否则我建议不要使用它,它就像一把非常锋利的刀。如果你不知道如何正确使用它,那么你会伤害自己。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-17
          • 1970-01-01
          相关资源
          最近更新 更多