如何在java中的并行程序中获得理想的线程数?
我需要在批处理程序中获得理想数量的线程,该程序在支持并行模式的批处理框架中运行,如Spring Batch中的并行步骤。
据我所知,执行程序步骤的线程太多并不好,可能会对程序的性能产生负面影响。 一些因素可能导致性能下降(上下文切换,使用共享资源时的竞争条件(锁定,同步……)……(还有其他因素吗?))。
当然,获得理想线程数的最佳方法是让我有实际的程序测试来调整程序的线程数。 但在我的情况下,实际测试并不容易,因为测试需要很多东西(人员,测试计划,测试数据等),这对我来说现在很难准备。 所以,在进行实际测试之前,我想知道如何尽可能地获得我的程序中可猜测的理想线程数。 我应该考虑什么来获得我的程序的理想线程数(步数)? CPU核心数? 我的程序运行的机器上的进程数? 数据库连接数? 在这样的情况下,是否存在诸如公式之类的理性方式?
最重要的考虑因素是您的应用程序/计算是CPU绑定还是IO绑定。
- 如果它受IO限制(单个线程花费大部分时间等待外部资源,如数据库连接,文件系统或其他外部数据源),那么您可以分配(许多)线程而不是可用处理器的数量 – 当然,有多少还取决于外部资源的扩展程度 – 本地文件系统,可能不是那么多。
- 如果它(大部分)受CPU限制,那么稍微超过可用处理器的数量可能是最好的。
我应该考虑什么来获得我的程序的理想线程数(步数)? CPU核心数? 我的程序运行的机器上的进程数? 数据库连接数? 在这样的情况下,是否存在诸如公式之类的理性方式?
如果没有对线程实际代码的大量了解,这将非常困难。 正如@Erwin所提到的,IO与CPU绑定操作是所需的知识的关键部分,在您确定即使应用程序的线程化会得到任何改进之前也是如此。 即使您确实找到了特定硬件的最佳位置,您也可以在另一台服务器(或虚拟云节点的不同实例)上启动,并查看截然不同的性能数字。
要考虑的一件事是在运行时更改线程数。 ThreadPoolExecutor.setCorePoolSize(...)
旨在在线程池运行后调用。 您可以手动暴露一些JMX挂钩来为您执行此操作。
您还可以允许应用程序在运行时监视应用程序或系统CPU使用情况,并根据该反馈调整值。 您还可以保留AtomicLong
吞吐量计数器,并在运行时上下AtomicLong
线程,以尝试最大化吞吐量。 然而,做到这一点可能会很棘手。
我通常会尝试:
- 对线号进行最佳猜测
- 检测您的应用程序,以便确定不同数量的线程的影响
- 允许它在运行时通过JMX进行调整,以便我可以看到影响
- 确保线程数是可配置的(可能通过系统属性),因此您不必重新发布以尝试不同的线程号
一般公式:
线程数<=(核心数)/ 1 - 阻塞因子
其中0 <=阻塞因子<1
一台机器的核心数: Runtime.getRuntime().availableProcessors()
您可以通过打印此代码获得并行度的线程数:
ForkJoinPool.commonPool()
数字并行度是你机器的核心数量 – 1.因为那个是主线程。
来源链接
时间:1:09:00