你是否担心多核技术?

13

毋庸置疑的是:多核计算机已经成为现实。

同样不可置疑的是:高效的多核编程相当困难。这不仅仅是了解pthread的问题。

对于“街头开发者”是否需要关注这些发展还有争议。

你对于必须扩展多核技能感到担忧吗?你所编写的软件是否适合并行化,如果适合,你是否正在学习相关技术(如果你之前不知道这些技术)?或者你认为操作系统会处理大部分事情,语言运行时也会尽其所能,你的应用程序愉快地在一个核上运行,让其他核去做它们的工作?


相比于多线程,多核有哪些新的问题?多线程是一个古老的话题,在GUI和数据处理中被广泛使用。 - DonkeyMaster
@DonkeyMaster 在多核情况下,缓存层次结构中的引用局部性是一个新问题。 - J D
20个回答

27

你的程序通常是CPU密集型的吗?

如果不是,那就不用管它了。这与你无关,并且可以使你的用户获得更流畅的体验而不对你造成任何要求。

很酷,对吧?

如果你的程序是CPU密集型的,并且你的问题可以并行处理,那么你可能可以利用多个核心。那就是开始担心的时候了。


来自评论:

改进答案的建议:大概解释如何判断你的程序是否是CPU密集型。 - Earwicker

CPU密集型意味着阻止程序运行更快的事情是缺乏计算能力。与IO密集型(或有时称为网络密集型)相比较。不良的主板和处理器选择也可能导致机器内存密集型(是的,我在看你,Alpha)。

因此,你需要知道你的程序从一刻到另一刻在做什么(以及机器的繁忙程度...)。要在类Unix系统上找出,请运行top命令。在Windows上,请使用任务管理器(感谢Roboprog)。

在负载小于每个核心1的机器上(也就是你不做什么的桌面机器),CPU密集型进程将始终占用超过50%的处理器(通常超过90%)。当负载平均值高于此时(例如,你有三个编译器、SETI@home和两个点对点网络在后台运行时),CPU密集型进程将占用大部分(# of cores)/(load average)


1
可能只是我,但我不确定你在这里说什么。 :( - Spencer Ruport
3
他的意思是,除非你的程序需要大量CPU资源,否则你甚至不需要处理多核问题。如果不需要,那么最好让你的程序仅使用一个核心,以释放CPU资源给其他程序使用。 - Dan Lew
完全正确。另一种说法是:让操作系统设计师去担心这个问题。 - Jon Ericson
2
改进答案的建议:大致解释如何判断程序是否受到 CPU 的限制。 - Daniel Earwicker
2
“任务管理器”是Windows中对“top”的说法,顺便提一下。 - Roboprog
显示剩余4条评论

21

顺便提一下:如果你的应用程序具有图形用户界面(GUI)且需要进行大量计算,请始终在单独的线程上进行强制性计算。忘记这样做是GUI冻结的原因。


5
当用户感知速度比实际速度更加重要时,这是绝对必要的。您的应用程序不应让用户感到沮丧。 - geofftnz
2
好建议。好的建议。但是这也是单核系统上的好建议。 - dmckee --- ex-moderator kitten
2
Google的Chromium博客描述了Chrome浏览器为将所有文件和网络I/O移动到后台线程所付出的巨大努力:http://blog.chromium.org/2008/10/responsiveness-for-plugins-and-renderer.html - Chris Peterson
4
希望微软Outlook团队注意到这一点 :( - RobS
1
先生,我向您推荐《最高指挥官》。在大规模战斗中,一切都很顺畅,直到您控制数百个单位。例如,我的标准攻击模式是300架T3飞艇组成的编队。这时游戏就会开始出现卡顿。 - tsilb
显示剩余4条评论

12

我不同意目前被接受的答案。

多核机器最重要的方面是CPU和主存储器相距很远。这意味着,除非应用程序是"尴尬地并行"或易于并行化,否则它很可能会成为内存绑定而不是CPU绑定。浮点数乘法需要约4个时钟周期,而从主存储器中获取数据需要数百个时钟周期。因此,利用缓存局部性变得很重要。

对于难以并行化的应用程序,如果单核心实现的性能足够好(大多数应用程序属于这一类),则无需并行化。但是,如果单核心性能不够好(或者你的竞争对手的应用程序在并行化方面更具响应性),那么你最好重构你的应用程序以更好地利用并行性和缓存局部性。笼统地说,重构后的应用程序将由相对独立(或者通信较少)的子模块组成,这些子模块可以并行运行(请参见此示例)。

请参见http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-183.html,了解多核和事物发展的良好概述。他们提到的主要观点是:

  • 时钟速度不再像以前那样增加。制造更多数量的较慢、较简单的核心比制造少量快速处理器更具成本效益。
  • 内存(日益)远离CPU
  • 几年之内,Web服务器将会有数千个核心,桌面电脑上则是数百个核心。因此,计划扩展您的应用程序(可能是自动扩展)到100个或1000个核心。这意味着您应该创建几个独立的任务。
  • 线程很难处理,最好使用“任务”

  • 一个注意点--时钟速度可能不会增加,但是在一个时钟周期内可以完成的工作量是可以增加的。 - rlbond
    @rlbond 可能您的意思是通过使用更多的流水线阶段可以完成更多的工作。但这并不是 - 指令级并行性 (ILP) 也有收益递减的趋势。可以通过使用多个核心而不是单个核心来完成更多的工作。 - amit kumar
    关于“内存墙”,请参见http://www.csl.cornell.edu/~sam/papers/cf04.pdf。 - amit kumar

    8

    这是一个开始学习函数式语言的好理由,因为它们更容易优化并行执行。


    2
    我会点赞,但我仍然坚持这一点:编写并行代码等待网络数据包(或按键、磁盘IO等)的到来,而这些数据包的时间尺度远远超出了操作系统时间片的范围,是没有任何收益的。 - dmckee --- ex-moderator kitten

    6

    我认为这个话题非常值得关注,姑且这么说吧。

    过去几十年中CPU速度的巨大提升无疑非常有价值,而未来的进一步提升同样有价值。

    但是,未来的提升主要将由核心数量的正常加倍组成。因此,为了从这些提升中受益,软件需要具备可并行性。

    许多应用程序中计算密集型的部分实际上是使用SQL编写的,因此它们已经具备了被RDBMS分解为并行任务的功能。所以那些人可以放心了。

    但是,对于我们大多数使用C#编写GUI的人来说,即使我们在编写GUI,也需要密切关注这方面的内容。GUI通常需要对其呈现给用户的模型执行某些有用的操作,当用户必须坐等完成时,他们会感到恼怒。在未来几年中,当他们查看任务管理器并发现他们新购买的32核机器仅利用了约3%时,他们甚至会更加恼怒。


    6
    是的,我也用线程编程。但我不够狂热,喜欢它们。无论你是超级人还是得到同事帮助,线程之间的交叉通信仍然很容易出现。线程容易实现,但正确地实现非常困难,所以当然会吸引Joe-Schmoe,而且它们很快!(当然这才是最重要的)
    在*nix上,fork()仍然是许多事情的好方法。开销不太大(是的,我有一天需要测量一下来支持我的BS),特别是如果你正在分叉一个解释器,然后在子进程中生成一堆任务特定的数据。
    话虽如此,在Windoze上,子进程的代价非常昂贵,据说。因此,Erlang方法看起来非常不错:强制Joe Schmoe编写纯函数,并使用消息传递,而不是他看似无限状态自动机全局(实例)变量混战,附加线程交叉通信盛宴。
    但我没有怨恨 :-)
    修订/评论:
    关于距离-内存的极好评论。最近我也一直在思考这个问题。标记-清除垃圾收集真的伤害了运行进程的“局部性”方面。在旧的80286上使用0等待状态RAM的M / S GC可能看起来无害,但在多级缓存体系结构上会带来很大的伤害。也许引用计数+分叉/退出并不是在某些情况下实现GC的坏主意?
    编辑:我花了一些精力来支持我的观点(结果因人而异):http://roboprogs.com/devel/2009.04.html

    使用消息传递...看吧,Win32的PostMessage很快就会重新流行起来 :) - gbjbaanb

    4

    我认为这是一个很好的问题。因此,我开始写了一系列关于它的博客文章在这里

    Dmckee的回答在最狭义的意义上是正确的。让我用自己的话重新表述一下,隐含地包括一些评论:

    对于不受CPU限制的操作,并行化没有任何价值。对于仅在短时间内(比如少于几百毫秒)受到CPU限制的操作,并行化的价值很小。实际上,这样做很可能会使程序更加复杂和有错误。学习如何实现细粒度并行性是复杂的,而且做好这件事是困难的。

    就其所及之处而言,这是正确的,但我认为对于更广泛的程序集合来说,答案更加丰富。实际上,在生产应用程序中使用多线程技术和隐式的多核技术有很多好处。例如,将磁盘和网络I/O操作移出用户界面线程对用户非常有益。

    这与增加计算操作的吞吐量无关,而是与保持程序用户界面的响应性有关。请注意,这里不需要图形用户界面 - 命令行程序、服务和基于服务器的应用程序也可以从中受益。
    我完全同意,将CPU绑定操作并行化通常是一项复杂的任务 - 需要了解细粒度同步、CPU缓存、CPU指令流水线等等。确实,这可能是经典的“难事”。
    但是,我认为需要这样做的情况很少;没有那么多问题需要这种细粒度的并行处理。是的!它们存在,而且您可能每天都会处理这些问题,但我认为在大多数开发人员的日常生活中,这是相当罕见的。
    即使如此,学习多线程和多核开发的基础知识也有很好的理由。
    1. 通过将较长的操作移出消息循环线程,它可以从用户的角度使程序更具响应性。 2. 即使对于不是CPU绑定的东西,将它们并行处理通常也是有意义的。 3. 它可以将复杂的单线程状态机拆分为更简单、更过程化的代码。
    事实上,操作系统已经为您做了很多工作,您可以使用支持多核的库(如 Intel's stuff)。但是,操作系统和库并非神奇 - 我认为大多数开发人员学习多线程编程的基础知识是有价值的。这将让您编写更好的软件,让用户更满意。
    当然,并不是所有程序都应该是多线程或多核启用的。对于一些简单的单线程实现,这也是可以接受的。因此,请谨慎判断,不要认为每个程序都应该是多线程的。但是,在许多方面,它通常是一种有价值的技术且非常有益的。如上所述,我计划从这里开始写一些博客。欢迎随时关注并发表评论。

    很好的回答。我特别喜欢“将一个CPU绑定操作变成并行化”的评论... :) - Drew Hall

    4
    我认为可能会发生的情况是,一旦大量核心(例如8个或更多)变得普遍,我们将看到开发利用并行性的应用程序,这在单线程世界中是不可行的。我想不出具体的例子,但考虑当3D加速器变得普遍时发生了什么。当时的游戏(比如《毁灭战士》)受制于其软件渲染代码的速度。高度详细的3D模型、模拟反射/折射和逐像素光照甚至都没有被考虑过。现在每个人都在使用。因此,除非您当前的应用程序高度依赖于CPU,否则不必担心并行化它们。如果您发现通过多个核心获得了大量的CPU资源,则可以考虑在新项目中利用它。

    +1,这正是我在回答中想要表达的 - 用户的期望将会改变,因此为了编写一个有竞争力的应用程序,您需要利用多核心技术,无论何时进入由用户控制长度的循环。 - Daniel Earwicker
    有很大的可能性我们会看到一个时代,内存和IO带宽会限制事物的发展,至少是消费级机器。更大(更智能)的芯片缓存是部分解决方案。改进的总线和主板架构则是其余的解决方案。 - dmckee --- ex-moderator kitten
    当然,我们将看到更多的后台索引、预计算和其他可能的技巧,但这些只有在几个核心和有限的内存带宽下并不值得。 - dmckee --- ex-moderator kitten
    2
    是的,内存带宽是致命问题。如果我们能够获得8GB缓存的CPU就好了... - geofftnz

    3
    没门!我是Clojure程序员!:D

    2

    我已经使用线程编程超过15年了。我一点也不担心。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接