2012-12-12 34 views
25

情景:我有一个示例应用程序,我有3个不同的系统配置 -基于no的线程配置。 CPU-核心

- 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能力,我想配置的没有。在应用程序级别的线程。但是,我希望在彻底了解系统功能之后才能做到这一点。

难道有一些方法(系统/模式/工具)来确定系统的实力,参考最大和最小编号。的线程,它可以最佳服务&而不会损失任何效率和性能。通过这个,我只能配置我的应用程序的那些值,这些值将充分公正,并为相应的硬件配置实现最佳性能。

已编辑1: 请问任何人请告诉任何关于如何为特定的硬件配置设置基准的读取。

Edited2: 为了使它更直接 - 希望学习/了解的任何资源/写起来,我可以阅读一般/整体水平获得关于线程的CPU管理一定的了解。

+0

我想查找最小值的最佳值。的线程/最大号码。基于上述系统配置的示例应用程序的线程数量,以实现最佳性能和完整的资源利用率。 – Santosh

+1

如果你不想用“启发式”的答案,剩下的只是实验设计。尝试一些设置,你一定会发现本地最大/最小值。 –

回答

57

要使用的最佳线程数取决于几个因素,但主要是可用处理器的数量以及您的任务的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为t他的等待时间比来计算时间(0为CPU密集型的任务,也许10或100慢速I/O任务)

因此,例如,在CPU绑定的情况下,您将有尽可能多的线程作为CPU(有人主张使用这个数字+ 1,但我从来没有看到它有重大差异)。

对于缓慢的I/O过程,例如Web爬虫,如果下载页面比处理页面慢10倍,则W/C可能为10,在这种情况下,使用100个线程将会很有用。

但是请注意,在实践中存在一个上限(使用10,000个线程通常不会加快速度,而且在使用正常内存设置启动它们之前,您可能会遇到OutOfMemoryError)。

如果您不了解应用程序运行环境的任何信息,这可能是您可以获得的最佳估计值。在生产环境中分析您的应用程序可能使您可以微调设置。

虽然没有严格相关,但您可能也对Amdahl's law感兴趣,它旨在测量您可以从并行程序中获得的最大加速。

+2

啊,好点,删除我以前的评论。 –

+0

如何获得W/C的估算值?我是否需要找到I/O vs Compute的确切时间? – AgentX

14

你可以提供给JVM的处理器的数量是这样的:

Runtime.getRuntime().availableProcessors() 

从可用的处理器数量计算线程的最佳数量是不幸的是不平凡不过。这很大程度上取决于应用程序的特性,例如对于具有比处理器数量更多的线程的CPU绑定应用程序没什么意义,而如果应用程序主要是IO绑定的,则可能需要使用更多线程。您还需要考虑系统上是否运行了其他资源密集型进程。

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

+0

矿是一个CPU密集型的过程。另外,我可以获得关于如何为特定h/w配置设置基线的任何读取。我可以通过任何方式查明特定处理器是否可以使用其所有可用资源,或者是否因其他软件正在运行而被阻塞。 – Santosh

+3

@Santosh如果它是CPU密集型的,那么使用'availableProcessors()'线程数应该接近最优。 – assylias

+0

我通常会添加一个小的常数因子来调度slop,以防其中一个线程在IO上被阻塞或什么东西... –

2

使用VisualVm工具监视线程。首先在程序中创建最小线程并查看其性能。然后增加程序中的线程数量并再次分析其性能。可以帮助您。

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在没有Admin权限的情况下运行,那么它不会意识到其他用户启动的进程(包括某些服务进程),所以它可能会不公平地与CPU资源进行竞争。

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

大多数的SMT将作为硬件核心报告或线程这些天,横跨每个核心缩放时这通常不是一件好事,因为一些应用程序进行优化一个SMT系统。更糟糕的是,查询核心是共享的(SMT)还是专用核心往往不能产生预期的结果。在某些情况下,操作系统本身根本不知道(例如,Windows 7并不知道AMD Bulldozer的共享核心设计)。如果您可以获得可靠的SMT计数,那么经验法则是将每个SMT计算为CPU密集型任务的半线程数,并将其作为大多数空闲任务的完整线程。但实际上,SMT的重量取决于其做什么样的计算,以及目标体系结构。例如,英特尔和AMD的SMT实施方式几乎相反,英特尔在运行并行加载整数和分支操作的任务方面表现强劲。 AMD公司在并行运行SIMD和内存操作方面表现强劲。

关于涡轮增压特点:

大多数CPU的这些天有内置的Turbo支持,进一步减轻了非常有效的价值得到了来自全国各地的系统的所有核心缩放。更糟糕的是,涡轮增压功能有时基于系统的实际温度,与CPU负载相同,所以塔本身的冷却系统本身对速度的影响与CPU规格相同。例如,在特定的AMD A10(推土机)上,我观察到它在两个线程上运行在3.7ghz。当第三个线程开始时,它降至3.5ghz,而第四个线程开始时降至3.4ghz。由于它是一个集成的GPU,当四个线程加上GPU工作时(A10 CPU在高负载情况下内部优先于GPU),它一路下降到大约3.0ghz;但仍可以通过2个线程和GPU激活来召集3.6ghz。由于我的应用程序使用了CPU和GPU,这是一个重要的发现。通过将进程限制为两个CPU绑定线程(另外两个共享内核仍然有用,它们作为GPU服务线程 - 能够唤醒并快速响应以将新数据推送到GPU),我能够提高整体性能,如所须)。

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

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

4

我同意这里的其他答案,推荐最佳猜测方法,并提供配置以覆盖默认值。此外,如果您的应用程序特别占用大量CPU资源,则可能需要考虑将应用程序“固定”到特定处理器。

你不说你的主要操作系统是什么,或者你是否支持多种操作系统,但大多数人都有这种方式。例如,Linux有taskset

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

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

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

与其他所有情况一样,这高度依赖于您运行的机器的体系结构以及其他运行的应用程序。

1

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

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

1

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

什么,我认为:

  1. 一次仅1中,节目的线程将在1个核心上执行。
  2. 具有2个线程的相同应用程序将在2个核心上执行一半的时间。
  3. 与4个线程相同的应用程序将执行更快的4核心。

所以你开发的应用程序应该有线程级< =无芯的。

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

阅读此内容以了解如何真正利用cpu核心的简单内容。 csharp-codesamples.com/2009/03/threading-on-multi-core-cpus/

1

不幸的是,从可用处理器的数量计算最佳线程数不是微不足道的。这很大程度上取决于应用程序的特性,例如对于具有比处理器数量更多的线程的CPU绑定应用程序没什么意义,而如果应用程序主要是IO绑定的,则可能需要使用更多线程。您还需要考虑系统上是否运行了其他资源密集型进程。