基于no的线程配置。 CPU核心

时间:2012-12-12 07:17:03

标签: java multithreading threadpool cpu akka

场景:我有一个示例应用程序,我有3种不同的系统配置 -

- 2 core processor, 2 GB RAM, 60 GB HHD,
- 4 core processor, 4 GB RAM, 80 GB HHD,
- 8 core processor, 8 GB RAM, 120 GB HHD

为了有效地利用我的应用程序的H / W功能,我希望配置no。应用程序级别的线程数。但是,我希望在彻底了解系统功能之后才能这样做。

可以通过某种方式(系统/模式/工具)来参考最大值和最小值来确定系统实力。线程可以最佳地服务和没有任何效率和性能损失。通过这种方式,我只能为我的应用程序配置那些能够完全正义并为各自的硬件配置实现最佳性能的值。

已编辑1: 任何人都可以建议任何有关如何为特定h / w配置设置基线的读数。

已编辑2: 为了使它更直接 - 希望学习/了解我可以阅读的任何资源/文章,以便在一般/整体层面上了解线程的CPU管理。

8 个答案:

答案 0 :(得分:61)

要使用的最佳线程数取决于几个因素,但主要是可用处理器的数量以及您的任务的CPU密集程度。 Java Concurrency in Practice提出了以下形式公式来估计最佳线程数:

N_threads = N_cpu * U_cpu * (1 + W / C)

其中:

  • N_threads是最佳线程数
  • N_cpu是prcessors的数量,您可以从Runtime.getRuntime().availableProcessors();
  • 获取
  • U_cpu是目标CPU利用率(如果要使用完整的可用资源,则为1)
  • W / C是等待时间与计算时间的比率(CPU绑定任务为0,慢速I / O任务可能为10或100)

因此,例如,在一个受CPU限制的场景中,你将拥有与CPU一样多的线程(一些主张使用该数字+ 1,但我从未见过它产生了显着的差异)。

对于缓慢的I / O流程,例如网络爬虫,如果下载页面的速度比处理速度低10倍,则W / C可能为10,在这种情况下,使用100个线程将非常有用。

但请注意,实际上有一个上限(使用10,000个线程通常不会加快速度,你可能会得到一个OutOfMemoryError,然后才能以正常的内存设置启动它们。)

如果您对运行应用程序的环境一无所知,这可能是您可以获得的最佳估计值。在生产中分析您的应用程序可能使您能够微调设置。

虽然没有严格的相关性,但您可能也对Amdahl's law感兴趣,{{3}}旨在衡量程序并行化可以带来的最大加速。

答案 1 :(得分:15)

我的建议是提供配置和命令行开关,用于分配每台机器的线程数。在用户/管理员未明确配置应用程序的情况下,使用基于Runtime.getRuntime()。availableProcessors()的启发式,如此处的其他答案所示。我 强烈 建议不要使用独有的基于启发式的线程到核心猜测,原因如下:

  • 大多数现代硬件正朝着越来越模糊的硬件线程方向发展:SMT模型,如英特尔的超线程和AMD的计算模块使公式复杂化(详情如下) ,并在运行时查询此信息可能很困难。

  • 大多数现代硬件都具有turbo功能,可根据活动核心和环境温度来调整速度。随着涡轮增压技术的改进,速度范围(ghz)也在增长。最近的一些英特尔和AMD芯片可以从2.6ghz(所有核心活动)到3.6ghz(单/双核活动),结合SMT可以意味着每个线程在前一种设计中获得了有效的1.6ghz - 2.0ghz吞吐量。目前无法在运行时查询此信息。

  • 如果您没有强有力的保证您的应用程序将是目标系统上运行的唯一进程,那么盲目地消耗所有cpu资源可能不会取悦用户或服务器管理员(取决于软件是否是用户应用程序或服务器应用程序。)

没有强大的方法可以在运行时了解机器其余部分的内容,而无需使用您自己的自制多任务内核替换整个操作系统。您的软件可以尝试通过查询进程和窥视CPU负载等进行有根据的猜测,但这样做很复杂,并且有用性仅限于特定类型的应用程序(您的应用程序可能符合条件),并且通常受益于或需要提升或特权访问级别。

  • 现代病毒扫描程序现在通过设置现代操作系统提供的特殊优先级标志来工作,例如。他们让操作系统告诉他们何时"系统闲置"。操作系统的决定不仅仅基于CPU负载:它还考虑了可能由电影播放器​​等设置的用户输入和多媒体标记。这对于大多数空闲任务来说很好,但对于CPU密集型任务(如你的。

  • 分布式家庭计算应用程序(BOINC,Folding @ Home等)通过定期查询正在运行的进程和系统CPU负载来工作 - 可能每秒或每半秒一次。如果在连续多个查询的不属于应用程序的进程上检测到加载,则应用程序将暂停计算。一旦某些查询的负载变低,它就会恢复。需要多次查询,因为CPU负载读数因短暂的峰值而臭名昭着。仍有一些警告:1。仍然鼓励用户手动重新配置BOINC以适应他们的机器规格。 2.如果BOINC在没有管理员权限的情况下运行,那么它就不会知道其他用户(包括某些服务进程)启动的进程,因此它可能会与那些CPU资源不公平地竞争。

关于SMT(超线程,计算模块):

现在大多数SMT都会报告为硬件核心或线程,这通常不太好,因为在SMT系统上的每个核心进行扩展时,很少有应用程序能够以最佳方式执行。更糟糕的是,查询核心是共享的(SMT)还是专用核心往往无法产生预期的结果。在某些情况下,操作系统本身并不知道(例如,Windows 7不知道AMD Bulldozer的共享核心设计)。如果您可以获得可靠的SMT计数,那么经验法则是将每个SMT计为CPU密集型任务的半个线程,并将其作为大多数空闲任务的完整线程。但实际上,SMT的重量取决于它所做的计算和目标架构。例如,英特尔和AMD的SMT实现几乎完全相反 - 英特尔在运行并行加载整数和分支操作的任务方面表现强劲。 AMD在并行运行SIMD和内存操作方面表现强劲。

关于Turbo功能:

如今大多数CPU都具有非常有效的内置Turbo支持,进一步降低了在系统所有内核中扩展所带来的价值。更糟糕的是,涡轮增压功能有时基于系统的实际温度和CPU负载,因此塔的冷却系统本身会影响CPU规格的速度。例如,在特定的AMD A10(Bulldozer)上,我观察到它在两个线程上以3.7ghz运行。第三个线程启动时降至3.5ghz,第四个启动时降至3.4ghz。由于它是一个集成的GPU,当四个线程加GPU工作时,它一直下降到大约3.0ghz(A10 CPU在高负载情况下内部优先考虑GPU);但仍然可以通过2个线程和GPU激活集合3.6ghz。由于我的应用程序同时使用了CPU和GPU,因此这是一个重要的发现。通过将进程限制为两个CPU绑定线程(另外两个共享核心仍然有用,它们作为GPU服务线程 - 能够唤醒并快速响应以将新数据推送到GPU,我能够提高整体性能,根据需要)。

...但与此同时,我在4x线程上的应用程序可能在安装了更高质量冷却设备的系统上表现更好。这一切都非常复杂。

结论:没有好的答案,而且由于CPU SMT / Turbo设计领域不断发展,我怀疑很快会有一个好的答案。你今天制定的任何体面的启发式明天都不会产生理想的结果。所以我的建议是:不要浪费太多时间。根据核心计数粗略猜测一些适合本地目的的东西,允许它被config / switch覆盖,然后继续。

答案 2 :(得分:14)

您可以像这样获得JVM可用的处理器数量:

Runtime.getRuntime().availableProcessors()

但遗憾的是,从可用处理器数量计算最佳线程数并非易事。这在很大程度上取决于应用程序的特性,例如,CPU绑定的应用程序具有比处理器数量更少的线程,而如果应用程序主要是IO绑定,则可能需要使用更多线程。您还需要考虑系统上是否正在运行其他资源密集型进程。

我认为最好的策略是根据每个硬件配置凭经验确定最佳线程数,然后在应用程序中使用这些数字。

答案 3 :(得分:4)

我同意这里的其他答案,建议采用最佳猜测方法,并提供覆盖默认值的配置。

此外,如果您的应用程序特别占用CPU,您可能需要考虑将应用程序“固定”到特定处理器。

您没有说明您的主要操作系统是什么,或者您是否支持多种操作系统,但大多数都有一些方法可以做到这一点。例如,Linux有taskset

常见的方法是避免CPU 0(始终由OS使用),并将应用程序的cpu亲和性设置为同一套接字中的一组CPU。

保持应用程序的线程远离cpu 0(如果可能,远离其他应用程序),通常可以通过减少任务切换量来提高性能。

将应用程序保存在一个套接字上可以通过减少缓存失效来进一步提高性能,因为您的应用程序的线程在cpu之间切换。

与其他所有内容一样,这在很大程度上取决于您运行的计算机的体系结构,以及运行的其他应用程序。

答案 4 :(得分:2)

使用VisualVm工具监视threads.First在程序中创建最小线程并查看其性能。然后再增加程序中的线程数,再次分析它的性能。可以帮助你。

答案 5 :(得分:1)

我在这里使用这个Python脚本来确定以最佳参数和人体工程学方式启动Java应用程序的内核(和内存等)的数量。 PlatformWise on Github

它的工作原理如下:编写一个python脚本,调用上面脚本中的getNumberOfCPUCores()来获取内核数,并getSystemMemoryInMB()来获取内存。您可以通过命令行参数将该通知传递给您的程序。然后,您的程序可以根据内核数使用适当数量的线程。

答案 6 :(得分:1)

在应用程序级别创建线程很好,在多核处理器中,在核心上执行单独的线程以提高性能。因此,为了利用核心处理能力,最好实现线程化。

我的想法:

  1. 每次只有一个程序的线程将在1个核心上执行。
  2. 2个线程的相同应用程序将在2个核心的半个时间执行。
  3. 4个线程的相同应用程序将在4核上执行得更快。

  4. 因此,您开发的应用程序应具有线程级别< = no of cores。

    线程执行时间由操作系统管理,是一种高度不可预测的活动。 CPU执行时间称为时间片或量子。如果我们创建越来越多的线程,操作系统会花费这个时间片的一小部分来决定哪个线程先行,从而减少每个线程获得的实际执行时间。换句话说,如果有大量的线程排队,每个线程都会做较少的工作。

    阅读本文以了解如何实际使用cpu core.Fantastic内容。 csharp-codesamples.com/2009/03/threading-on-multi-core-cpus/

答案 7 :(得分:1)

但遗憾的是,从可用处理器数量计算最佳线程数并非易事。这在很大程度上取决于应用程序的特性,例如,CPU绑定的应用程序具有比处理器数量更少的线程,而如果应用程序主要是IO绑定,则可能需要使用更多线程。您还需要考虑系统上是否正在运行其他资源密集型进程。