我最近继承了一个小型Java程序,它从大型数据库中获取信息,进行一些处理并生成有关信息的详细图像。原作者使用单个线程编写代码,然后对其进行修改以允许它使用多个线程。
在代码中他定义了一个常量;
// number of threads
public static final int THREADS = Runtime.getRuntime().availableProcessors();
然后设置用于创建图像的线程数。
我理解他的理由是线程数不能大于可用处理器的数量,因此请将其设置为从处理器中获取全部潜力的数量。它是否正确?或者是否有更好的方法来充分利用处理器的潜力?
编辑:为了进一步澄清,正在线程化的特定算法会扩展到正在创建的图片的分辨率(每个像素1个线程)。这显然不是最好的解决方案。该算法所做的工作是一直需要的工作,并且是完全数学运算,没有锁或其他因素会导致任何给定的线程休眠。我只想最大化程序CPU利用率,以减少完成时间。
答案 0 :(得分:15)
线程很好,但正如其他人所说,你必须高度意识到你的瓶颈。您的算法听起来很容易受到多个CPU之间的缓存争用的影响 - 这尤其令人讨厌,因为它有可能达到所有线程的性能(通常您会想到使用多个线程在等待缓慢或高速时继续处理延迟IO操作)。
缓存争用是使用多CPU处理高度并行化算法的一个非常重要的方面:确保考虑到内存利用率。如果您可以构造数据对象,以便每个线程都有自己正在处理的内存,那么可以大大减少CPU之间的缓存争用。例如,拥有大量的int并使不同的线程处理该阵列的不同部分可能更容易 - 但在Java中,对该阵列的边界检查将尝试访问内存中的相同地址,可能导致给定的CPU必须从L2或L3缓存重新加载数据。
将数据拆分为自己的数据结构,并配置这些数据结构,使它们是线程本地的(甚至可能更优化使用ThreadLocal - 实际上使用操作系统中的结构来保证CPU可以用于优化缓存。
我能给你的最好的建议是测试,测试,测试。不要假设CPU将如何执行 - 这些天CPU中存在巨大的大量魔法,通常会产生违反直觉的结果。另请注意,JIT运行时优化将在此处添加额外的复杂层(可能很好,可能不是)。
答案 1 :(得分:10)
一方面,你想要认为Threads == CPU / Cores非常有意义。为什么有一个线程,如果没有什么可以运行它?
细节归结为“线程在做什么”。空闲等待网络数据包或磁盘块的线程浪费了CPU时间。
如果你的线程CPU很重,那么1:1的相关性是有道理的。如果你有一个“读取数据库”线程,它提供其他线程,并且单个“转储数据”线程并从CPU线程中提取数据并创建输出,那么这两个很可能很容易共享CPU而CPU重线程一直在搅拌。
与各种事物一样,真正的答案就是衡量它。由于该数字是可配置的(显然),请配置它!用1:1线程运行它到CPU,2:1,1.5:1,无论如何,并为结果计时。快一胜。
答案 2 :(得分:3)
您的应用程序需要的数量;不多也不少。
显然,如果您正在编写一个包含某些并行算法的应用程序,那么您可以开始基准测试以找到线程数量的良好平衡,但请记住,数百个线程不会加速任何操作
如果你的算法无法并行化,那么没有多少额外的线程可以提供帮助。
答案 3 :(得分:1)
是的,这是一种非常合理的方法。每个处理器/核心一个线程将最大化处理能力并最小化上下文切换。除非我通过基准测试/分析发现问题,否则我可能会保留原样。
需要注意的一点是,JVM不保证availableProcessors()
是恒定的,所以从技术上讲,你应该在产生线程之前立即检查它。我怀疑这个值在典型的计算机上可能会在运行时发生变化。
P.S。正如其他人所指出的,如果您的进程不受CPU限制,那么这种方法不太可能是最优的。既然你说这些线程用于生成图像,我假设你 CPU绑定。
答案 4 :(得分:1)
处理器数量是一个良好的开端;但如果这些线程做了很多i / o,那么可能会更好......或更少。
首先考虑可用资源是什么以及您希望优化什么(完成时间最短,对其他任务的影响最小等)。然后做数学。
有时候,如果你为每个i / o资源专门设置一个或两个线程,而其他人争夺CPU,那可能会更好。在这些设计中,分析通常更容易。
答案 5 :(得分:0)
使用线程的好处是通过允许程序在作业的不同部分工作而另一部分正在等待某些事情发生(通常是I / O)来减少程序的挂钟执行时间。如果你的程序完全是CPU绑定的,那么添加线程只会降低它的速度。如果它是完全或部分I / O绑定,添加线程可能有所帮助,但是在添加线程的开销和将要完成的额外工作之间存在一个平衡点。如果程序完全或几乎完全受CPU限制,那么使线程数等于处理器数将产生最佳性能。
与许多关于“应该”一词的问题一样,答案是“它取决于”。如果您认为可以获得更好的性能,请向上或向下调整线程数并对应用程序的性能进行基准测试。还要考虑可能影响决策的任何其他因素(如果您的应用程序占用计算机100%的可用功率,其他应用程序的性能将会降低)。
这假设多线程代码写得正确等。如果原始开发人员只有一个CPU,他将永远不会有机会遇到写得不好的线程代码问题。因此,在调整线程数时,您应该测试行为和性能。
顺便说一下,您可能需要考虑允许在运行时配置线程数而不是编译时间,以使整个过程更容易。
答案 6 :(得分:0)
看到你的编辑后,每个CPU的一个线程很可能和它一样好。您的应用程序似乎可以并行化。如果您有额外的硬件,您可以使用GridGain为您的应用程序启用网格,并让它在多台计算机上运行。这可能是唯一的事情,除了购买更快/更多核心,这将加快它。