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

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

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

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

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

我理解他的理由是线程数不能大于可用处理器的数量,因此将其设置为从处理器中获取全部潜力的数量。 它是否正确? 或者是否有更好的方法来充分利用处理器的潜力?

编辑:为了进一步澄清,正在线程化的特定算法扩展到正在创建的图片的分辨率(每个像素1个线程)。 这显然不是最好的解决方案。 该算法所做的工作是一直需要的,并且是完全数学运算,没有锁或其他因素会导致任何给定的线程hibernate。 我只想最大化程序CPU利用率,以减少完成时间。

线程很好,但正如其他人所说,你必须高度意识到你的瓶颈。 您的算法听起来很容易受到多个CPU之间的缓存争用的影响 – 这尤其令人讨厌,因为它有可能达到所有线程的性能(通常您会想到使用多个线程继续处理,同时等待慢或高延迟IO操作)。

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

将数据拆分为自己的数据结构,并配置这些数据结构,使它们是线程本地的(甚至可能更优化使用ThreadLocal – 实际上使用OS中的结构,提供CPU可用于优化缓存的保证。

我能给你的最好建议是测试,测试,测试。 不要假设CPU将如何执行 – 这些天CPU中存在大量的魔力,通常会产生违反直觉的结果。 另请注意,JIT运行时优化将在此处添加额外的复杂层(可能很好,可能不是)。

一方面,你想要认为Threads == CPU / Cores非常有意义。 为什么有一个线程,如果没有什么可以运行它?

细节归结为“线程在做什么”。 空闲等待网络数据包或磁盘块的线程浪费了CPU时间。

如果您的线程CPU很重,那么1:1的相关性就会有所帮助。 如果你有一个“读取数据库”线程来提供其他线程,并且单个“转储数据”线程并从CPU线程中提取数据并创建输出,那么这两个很可能很容易共享CPU而CPU重线程继续搅拌。

与各种事物一样,真正的答案就是衡量它。 由于该数字是可配置的(显然),请配置它! 用1:1线程运行它到CPU,2:1,1.5:1,无论如何,并为结果计时。 快一胜。

您的应用程序需要的数量; 不多也不少。

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

如果您的算法无法并行化,那么没有多少额外的线程可以提供帮助。

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

需要注意的一点是,JVM不保证availableProcessors()将是常量,因此从技术上讲,您应该在生成线程之前立即检查它。 我怀疑这个值在典型的计算机上可能会在运行时发生变化。

PS正如其他人所指出的那样,如果你的进程不受CPU限制,那么这种方法不太可能是最优的。 既然你说这些线程用于生成图像,我认为你 CPU绑定的。

处理器数量是一个良好的开端; 但如果这些线程做了很多i / o,那么可能会更好……或更少。

首先想一想可用的资源是什么,你想要优化什么(最短的完成时间,对其他任务的影响最小等)。 然后做数学。

有时候,如果你为每个i / o资源专门设置一个或两个线程,那么其他人可能会争用更好的CPU。 在这些设计中,分析通常更容易。

使用线程的好处是通过允许程序在作业的不同部分工作而另一部分正在等待某些事情发生(通常是I / O)来减少程序的挂钟执行时间。 如果你的程序完全是CPU绑定的,那么添加线程只会降低它的速度。 如果它是完全或部分I / O绑定,添加线程可能会有所帮助,但是在添加线程的开销和将要完成的额外工作之间有一个平衡点。 如果程序完全或几乎完全受CPU限制,那么使线程数等于处理器数将产生最佳性能。

正如许多关于“应该”这个词的问题一样,答案是“它取决于”。 如果您认为可以获得更好的性能,请调整线程的数量,并对应用程序的性能进行基准测试。 还要考虑可能影响决策的任何其他因素(如果您的应用程序正在吃掉100%的计算机可用马力,其他应用程序的性能将会降低)。

这假设multithreading代码写得正确等。如果原始开发人员只有一个CPU,他将永远不会有机会遇到写得不好的线程代码问题。 因此,在调整线程数时,您应该测试行为和性能。

顺便说一下,您可能需要考虑允许在运行时配置线程数而不是编译时间,以使整个过程更容易。

在看到你的编辑之后,每个CPU的一个线程很可能和它一样好。 您的应用程序似乎可以并行化。 如果您有额外的硬件,您可以使用GridGain为您的应用程序启用网格,并让它在多台计算机上运行。 除了购买更快/更多核心之外,这可能是唯一能够加快速度的因素。