我最近了解到,有时人们会将特定的进程或线程锁定到特定的处理器或内核,并且认为这种手动调优将最好地分配负载。这对我来说有点违反直觉 - 我认为操作系统调度程序能够比人类更好地决定如何分散负载。我可以看到,对于较旧的操作系统来说,这可能是不正确的,例如他们在特定核心对之间的延迟,或者一对核心之间的共享缓存,而不是另一对核心之间的共享缓存。但我认为像Linux,Solaris 10,OS X和Vista这样的“现代”操作系统应该有知道这些信息的调度程序。我错了他们的能力吗?我错了,操作系统实际上可以解决这个问题吗?我对Solaris和Linux的答案特别感兴趣。

结果是我是否需要告知用户我的(多线程)软件如何考虑在他们的盒子上进行平衡。

有帮助吗?

解决方案

首先,'锁'不是描述它的正确术语。 “亲和力”是更合适的术语。

在大多数情况下,您无需关心它。但是,在某些情况下,手动设置CPU /进程/线程关联可能是有益的

操作系统通常无视现代多核架构的细节。例如,假设我们有2插槽四核处理器,处理器支持 SMT (= HyperThreading )。在这种情况下,我们有2个处理器,8个内核和16个硬件线程。因此,OS将看到16个逻辑处理器。如果操作系统无法识别此类层次结构,则极有可能失去一些性能提升。原因是:

  1. 缓存:在我们的示例中,两个不同的处理器(安装在两个不同的套接字上)不共享任何片上缓存。假设一个应用程序有4个繁忙运行的线程,并且许多数据由线程共享。如果操作系统调度处理器中的线程,那么我们可能会丢失一些缓存局部性,从而导致性能下降。但是,线程不共享很多数据(具有不同的工作集),然后通过增加有效的缓存容量来分离到不同的物理处理器会更好。此外,可能会发生更棘手的情况,操作系统很难意识到这一点。

  2. 资源冲突:让我们考虑一下SMT(= HyperThreading)案例。 SMT共享许多重要的CPU资源,如缓存,TLB和执行单元。假设只有两个忙线程。但是,操作系统可能会愚蠢地在同一物理核心的两个逻辑处理器上安排这两个线程。在这种情况下,两个逻辑线程争用大量资源。

  3. 一个很好的例子是Windows 7. Windows 7现在支持考虑SMT的智能调度策略(相关文章)。 Windows 7实际上阻止了上述2.情况。以下是Windows 7中任务管理器的快照,Core i7负载为20%(具有超线程的四核处理器= 8个逻辑处理器):


    (来源: egloos.com

    CPU使用历史非常有趣,不是吗? :)你可能会看到只使用一对CPU ,这意味着Windows 7避免同时在同一个核心上同时调度两个线程。这项政策肯定会减少资源冲突等SMT的负面影响。

    我想说操作系统不是很聪明,无法理解现代多核架构,其中有很多缓存,共享最后一级缓存,SMT,甚至是NUMA。因此,您可能需要手动设置CPU /进程/线程关联性。

    但是,我不会说这是真的需要。只有当您完全了解工作负载模式和系统体系结构时,才能尝试使用它。并且,看看您的尝试是否有效的结果。

其他提示

对于通用应用程序,没有理由设置CPU亲和性;您应该只允许OS调度程序选择应该运行进程或线程的CPU。但是,有些情况需要设置CPU亲和性。例如,在实时系统中,将线程从一个核心迁移到另一个核心的成本(如果未设置CPU亲和性,可能会在任何时间发生)可能会引入不可预测的延迟,从而导致任务错过最后期限,以及排除实时保证。

您可以查看这篇文章关于实时CORBA的多核意识实现除此之外,还必须设置CPU亲和性,以便CPU迁移不会导致错过最后期限。

该论文是:多处理器的实时性能和中间件和多核Linux平台

对于设计了并行性和多核心的应用程序,OS默认的线程关联有时是不够的。有许多并行方法,但到目前为止,所有方法都需要程序员和知识的参与 - 至少在某种程度上 - 是解决方案所映射的体系结构。这包括所涉及的机器,CPU和线程。

这是一个积极研究的课程,麻省理工学院的开放式课程有一个很好的课程,可以深入研究这些问题: http://ocw.mit.edu/OcwWeb/Electrical-Engineering-and-Computer-Science/6-189January--IAP --2007 / CourseHome /

很多人在这里没有想到的是禁止两个进程在同一处理器(套接字)上运行的想法。可能值得帮助系统将不同的大量使用的进程绑定到不同的处理器。如果调度程序不够聪明,无法自行解决,这可以避免争用。

但这更像是一个系统管理员任务,然后是程序员的任务。对于一些高性能数据库服务器,我已经看到了这样的优化。

大多数现代操作系统都可以在核心之间分配工作。他们还试图让线程在同一个核心上运行,以获得你提到的缓存优势。

一般情况下,除非您有充分的理由,否则永远不应该设置线程关联。您没有像操作系统那样深入了解系统中的线程所做的其他工作。内核不断根据新的处理器技术进行更新(每个插槽单CPU,超线程到每个插槽多个内核)。您设置硬性关系的任何尝试都可能适用于未来的平台。

MSDN杂志上的这篇文章, 使用并发性来实现可扩展性 ,很好地概述了Win32上的多线程。关于CPU亲和力,

  

Windows自动使用   所谓的理想处理器亲和力   尝试最大化缓存   效率。例如,一个线程   在获得上下文的CPU 1上运行   转出将更喜欢再次运行   在CPU 1上希望它的一些   数据仍将驻留在缓存中。但   如果CPU 1忙,而CPU 2不忙,则   可以在CPU 2上安排线程   相反,所有的负缓存   暗示的效果。

该文章还警告说,如果不深入了解问题,就不应该操纵CPU亲和力。根据这些信息,我对你的问题的回答将是“否”,除非是非常具体,易于理解的情况。

我甚至不确定你是否可以将进程固定到linux上的特定CPU。所以,我的答案是“否”。 - 让操作系统处理它,它大部分时间都比你聪明。

编辑: 似乎在win32上你可以控制你将在哪个CPU系列上运行这个过程。现在我只等着有人在linux / posix上证明我错了......

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top