问题 如何优化双,四和更高的多处理器?


伙计们,我已经编写了20多年的高速软件,并且几乎了解了本书中的每一个技巧,从微型工作台制作合作,分析,用户模式多任务处理,尾递归,你在Linux,Windows上为它提供了非常高性能的东西。 , 和更多。

问题是,当CPU密集型工作的多个线程暴露给多核处理器时,我发现自己会感到困惑。

在线程之间(在不同核心上)共享日期的各种方式的微观基准中的性能结果似乎不符合逻辑。

很明显,核心之间存在一些“隐藏的交互”,这与我自己的编程代码并不明显。我听说过L1缓存和其他问题,但这些对我来说是不透明的。

问题是:我在哪里可以学到这些东西?我正在寻找一本关于多核处理器如何工作,如何编程以利用其内存缓存或其他硬件架构的深度书,而不是受到它们的惩罚。

任何建议或伟大的网站或书籍?经过多次谷歌搜索,我空洞了。

此致 韦恩


5287
2017-12-26 04:42


起源

我认为很大程度上取决于你想要完成的事情。服务器端v.s.桌面,图形vs.文本处理v.s.模拟核爆炸;几十个任务的高吞吐量。 10,000个任务的低延迟。你有兴趣了吗? - Bill
好的。好问题。我们基本上构建了一个CEP(复杂事件处理)系统,它必须在软实时中每秒处理数百万个小数据。从理论上讲,单核上的性能表明,通过将X 4乘以四核或X 8,可以实现必要的性能。数据需要从差异源流动到组合,然后以不同方式与客户端相乘。每个步骤都需要CPU处理或I / O,因此我们使用Interlocked构建了无锁定的协作用户模式多任务。但是存在令人费解的(至今)性能问题。 - Wayne
您可能会关注另一件事: 1024cores.net/home/parallel-computing/taxi-paths/... - gjvdkamp


答案:


这本书教会了我很多关于为什么没有必要使用原始CPU功率这一类问题的唯一注意事项。我几年前在研究生院里用它,但我认为所有的原则仍然适用:

http://www.amazon.com/Computer-Architecture-Quantitative-Approach-4th/dp/0123704901

基本上,多进程配置中的一个主要问题是同步对主内存的访问,如果你不这样做,它可能是性能的真正瓶颈。这些缓存必须保持同步,这非常复杂。


4
2017-12-26 04:48



是的,这是他需要的书。尤其是第4章。 - ThomasMcLeod
是的,这个似乎涵盖了所有,删除了我的帖子。 - gjvdkamp
显示我的年龄,我的副本实际上是我在斯坦福大学Hennessey的建筑课上学到的这本书的预发布版本。他是一位非常好的老师。毫不奇怪,他继续担任大学校长。 - Francis Upton
弗朗西斯,你对这本书的评论似乎涉及最关键的问题。我会看看这本书。如果这是你们所有人都说的那样,那么我会选择你作为正确的答案,弗朗西斯。 - Wayne


我自己的问题,回答,在stackoverflow的姐妹网站上: https://softwareengineering.stackexchange.com/questions/126986/where-can-i-find-an-overview-of-known-multithreading-design-patterns/126993#126993

我将复制答案以避免点击:

引用鲍里斯:

使用Microsoft .NET并行编程:设计模式   多核架构的分解与协调 http://rads.stackoverflow.com/amzn/click/0735651590

这是一本书,我全心全意地推荐。

它是:

新的 - 去年出版。意味着你没有阅读有点过时   实践。

简短 - 大约200多页,信息密集。这些   阅读时间过多,阅读1000多页的时间太少   图书。

易于阅读 - 不仅写得很好,而且它   以简单易读的方式介绍难以掌握的概念。

打算教 - 每章都提供练习。我知道它是   总是有益于这些,但很少这样做。这本书非常给出   令人信服的有趣任务。令人惊讶的是我做了大部分和   喜欢这样做。

另外,如果你想了解更多低级细节,这是我找到的最好的资源:“多处理器编程的艺术“它是用java作为代码示例编写的,它与我的C#背景很好地配合。

PS:我有大约5年的“硬核”并行编程经验,(abet使用C#)所以希望你能相信我,当我说“多处理器编程的艺术“岩石


4
2017-12-26 09:18






2
2017-12-26 04:54





并行化代码导致意外不良的一个特定原因是 虚假分享如果你不知道那里发生了什么(你没有),你不会看到即将到来。这里有两篇文章讨论.Net的原因和补救措施:

http://msdn.microsoft.com/en-us/magazine/cc872851.aspx

http://www.codeproject.com/KB/threads/FalseSharing.aspx

Rgds GJ


2
2017-12-29 11:40



它声称解决了这个问题,但只有当所有数据都包含在一个对象中时才会这样做(在本例中是一个值类型数组)。 .NET无法控制不同对象的存储,您需要使用本机代码来避免在复杂的真实场景中进行错误共享。 - Ben Voigt
你对对象所在的位置几乎没有控制权是正确的,但是你可以在内存(同一个对象或一个数组)中猜测数据何时靠近。然后,您可以控制如何在线程/任务之间对工作进行分区,因此它们不会对相邻数据进行操作。这应该允许您最小化问题。 - gjvdkamp


我发现这个链接专门解释了这个问题 在影响我的CPU上的多核缓存处理 多线程程序。

http://www.multicoreinfo.com/research/intel/mem-issues.pdf

整个网站multicoreinfo.com有很多好处 关于多核编程的信息和参考。


0
2017-12-31 01:39



哇一篇关于虚假分享的文章,但接下来是c ++。多么聪明的你自己想出来的一切! - gjvdkamp
为什么有人投票呢? - Wayne


需要不同方法的多线程有不同的方面。

例如,在Web服务器上,广泛使用线程池,因为它被认为是“有利于”性能的。这样的池可能包含数百个等待投入工作的线程。使用那么多线程会导致调度程序超时工作,这对性能有害,但在Linux系统上是无法避免的。对于Windows,选择的方法是IOCP机制,它建议许多线程不大于安装的核心数。它导致应用程序成为(I / O完成)事件驱动,这意味着轮询不会浪费任何循环。涉及的少数线程将调度程序工作减少到最少。

如果对象要实现可扩展的功能(更多内核<=>更高性能),那么主要问题将是内存总线饱和。由于代码获取,数据读取和数据写入,将发生饱和。使用两个线程而不是一个线程,错误实现的代码将运行得更慢。解决这个问题的唯一方法是通过主动减少内存总线工作:

  • 将代码定制到最小的内存占用(=适合代码缓存)并且不调用其他函数或跳转到整个地方。
  • 定制内存读取和写入到最小大小。
  • 通知预读机制即将进行的RAM读取。
  • 定制工作,使核心自身缓存(L1和L2)内部工作的比例与外部工作(L3和RAM)相比尽可能大。

换句话说:将适用的代码和数据块放入尽可能少的缓存行(每个64字节),因为最终这将决定可扩展性。如果缓存/内存系统能够每秒执行x个缓存行操作,那么如果每个工作单元(=> x / 5)而不是十一(x / 11)或五十二个需要五个缓存行,则代码将运行得更快(X / 52)。

实现这一目标并非易事,因为它每次都需要或多或少的独特解决方案。有些编译器可以很好地利用主机处理器的流水线操作进行指令排序。这并不一定意味着它将是多核的良好排序。

可扩展代码的有效实现不一定是非常好的。推荐的编码技术和样式最终可能会妨碍代码的执行。

我的建议是通过在低级语言(例如C)中编写一个简单的多线程应用程序来测试其工作原理,该语言可以调整为在单线程或多线程模式下运行,然后分析不同模式的代码。您需要在指令级别分析代码。然后,您将尝试使用不同的(C)代码构造,数据组织等。您可能需要在框外思考并重新考虑算法,以使其更加缓存友好。

第一次需要大量的工作。您将无法了解适用于所有多线程解决方案的内容,但您可能会了解在分析配置文件代码时不应该做什么以及需要注意什么。


0
2018-02-13 17:23