我在Java程序中应该使用多少个线程?

18

最近我继承了一个小的Java程序,它从一个大型数据库中获取信息,进行一些处理并生成有关该信息的详细图像。原作者使用单个线程编写了代码,然后稍后对其进行了修改,以允许它使用多个线程。

在代码中,他定义了一个常量;

//  number of threads
public static final int THREADS =  Runtime.getRuntime().availableProcessors();

然后设置用于创建图像的线程数量。

我理解他的想法是线程数不能大于可用处理器的数量,因此将其设置为可以充分发挥处理器潜力的数量。这正确吗?还是有更好的方法来利用处理器的全部潜力?

编辑:为了更明确一些,正在进行多线程处理的特定算法会按比例缩放所创建图片的分辨率(每个像素一个线程)。显然,这不是最佳解决方案。该算法所做的工作是耗时的数学运算,没有锁或其他因素会导致任何给定线程休眠。我只想最大化程序的 CPU 利用率以缩短完成时间。

7个回答

19

线程是可以使用的,但正如其他人所指出的那样,您必须高度了解瓶颈。您的算法听起来容易受到多个CPU之间缓存争用的影响 - 这特别危险,因为它有可能影响所有线程的性能(通常当您想使用多个线程来继续处理同时等待缓慢或高延迟IO操作时)。

缓存争用是使用多个CPU处理高度并行算法的非常重要的方面:确保考虑内存利用率。如果您可以构造您的数据对象,使每个线程都有自己正在处理的内存,您就可以大大减少CPU之间的缓存争用。例如,可能更容易拥有一组int的大数组,并使不同的线程在该数组的不同部分上工作 - 但在Java中,该数组的边界检查将尝试访问内存中的相同地址,这可能导致某个CPU必须从L2或L3缓存重新加载数据。

将数据拆分成自己的数据结构,并配置这些数据结构,使它们是线程本地的(甚至可能更优化使用ThreadLocal-它实际上使用操作系统中提供的构造来提供保证,以便CPU可以优化缓存。

我可以给你的最好建议是测试、测试和测试。不要对CPU的性能表现做出假设 - 现代CPU中有大量的魔法正在发生,通常会产生反直觉的结果。还要注意JIT运行时优化将在这里添加一个额外的复杂层面(也许是好的,可能不是好的)。


15

一方面,你可能认为线程==CPU/核心是完全有道理的。如果没有要运行的东西,为什么要有线程呢?

关键在于“线程正在做什么”。一个空闲等待网络数据包或磁盘块的线程会浪费CPU时间。

如果你的线程很重CPU,则1:1的对应关系是有意义的。如果你有一个单独的“读取数据库”线程来提供给其他线程数据,并且有一个单独的“转储数据”的线程从CPU线程中提取数据并创建输出,那么这两个线程很可能可以共享一个CPU,而CPU重的线程继续工作。

像所有事物一样,真正的答案是进行测量。由于数字是可配置的(显然),所以配置它!以1:1的线程到CPU比例、2:1、1.5:1等方式运行,并计算结果时间。速度最快的胜出。


4

你的应用程序所需的数量,既不多也不少。

显然,如果你正在编写一个包含一些可并行化算法的应用程序,则可以开始进行基准测试,以找到线程数量的良好平衡,但请注意,数百个线程不会加速任何操作。

如果你的算法无法并行化,那么任何额外的线程数量都无济于事。


2

是的,这是一个完全合理的方法。每个处理器/核心一个线程将最大化处理能力并最小化上下文切换。除非通过基准测试/分析发现问题,否则我可能会保留原样。

需要注意的一点是JVM不保证availableProcessors()是恒定的,因此在生成线程之前应立即检查它。虽然我认为在典型计算机上这个值在运行时不太可能改变。

P.S. 正如其他人指出的,如果您的进程不受CPU限制,这种方法可能不是最优的。但由于您说这些线程用于生成图像,因此我假设您是受CPU限制的。


1

处理器数量是一个不错的起点;但如果这些线程执行大量的I/O操作,那么可能需要更多或更少的处理器。

首先考虑可用资源以及您想要优化什么(完成所需时间最短、对其他任务影响最小等),然后进行计算。

有时候,如果您将一两个线程专门用于每个I/O资源,而其他线程则争夺CPU,则可能会更好。这些设计通常更容易进行分析。


0
使用线程的好处是通过允许程序在等待某些事情发生(通常是I/O)的同时,工作于工作的不同部分,从而减少程序的墙钟执行时间。如果您的程序完全受CPU限制,则添加线程只会使其变慢。如果它完全或部分受I/O限制,则添加线程可能有所帮助,但需要在添加线程的开销和完成的额外工作之间达到平衡点。如果将线程数设置为处理器数,如果程序完全或接近完全受CPU限制,则可以获得最佳性能。
对于许多带有“应该”一词的问题,答案是“取决于情况”。如果您认为可以获得更好的性能,请调整线程数并基准测试应用程序的性能。还要考虑可能影响决策的任何其他因素(如果您的应用程序占用了计算机可用马力的100%,则其他应用程序的性能将降低)。
这假定多线程代码已经编写正确等。如果原始开发人员只有一个CPU,他永远不会有机会体验到编写不良线程代码的问题。因此,在调整线程数时,您应该测试行为以及性能。
顺便提一下,您可能希望考虑允许在运行时配置线程数,而不是编译时,以使整个过程更容易。

0

看到您的编辑后,每个 CPU 一个线程可能是最好的选择。您的应用程序似乎非常可并行化。如果您有额外的硬件,可以使用 GridGain 将您的应用程序网格化,并在多台计算机上运行。这可能是除购买更快/更多核心之外唯一能加速它的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接