【问题标题】:How are you taking advantage of Multicore?您如何利用多核?
【发布时间】:2010-09-26 16:10:47
【问题描述】:

作为来自企业 Web 开发领域的 HPC 世界中的某个人,我总是很想知道“现实世界”中的开发人员如何利用并行计算。现在这比all chips are going multicore 更相关,当芯片上有数千个内核而不是几个内核时,它会更加相关。

我的问题是:

  1. 这对您的软件路线图有何影响?
  2. 我对有关多核如何影响不同软件领域的真实故事特别感兴趣,因此请在回答中说明您所做的开发类型(例如服务器端、客户端应用程序、科学计算等)。
  3. 您如何处理现有代码以利用多核计算机,您面临哪些挑战?您使用的是OpenMPErlangHaskellCUDATBBUPC 还是别的什么?
  4. 随着并发级别的不断提高,您打算做什么?您将如何处理成百上千个内核?
  5. 如果您的领域不容易从并行计算中受益,那么解释为什么也很有趣。

最后,我将这个问题描述为一个多核问题,但请随意讨论其他类型的并行计算。如果您要移植应用程序的一部分以使用 MapReduce,或者如果大型集群上的 MPI 是您的范例,那么也一定要提到这一点。

更新:如果您确实回答了第 5 个问题,请提及您是否认为如果内核数(100、1000 等)超过可用内存带宽所能提供的数量(参见就像每个核心的带宽越来越小)。您还能将剩余的内核用于您的应用程序吗?

【问题讨论】:

    标签: concurrency scalability parallel-processing multicore


    【解决方案1】:

    我的研究工作包括编译器和垃圾邮件过滤方面的工作。我还做了很多“个人生产力”的 Unix 工作。此外,我编写和使用软件来管理我所教的课程,包括评分、测试学生代码、跟踪成绩以及无数其他琐事。

    1. 多核对我没有任何影响,除了作为编译器支持其他应用程序的研究问题。但这些问题主要在于运行时系统,而不是编译器。
    2. Dave Wortman 在 1990 年左右证明您可以并行化编译器以保持四个处理器忙碌。我认识的人都没有重复过这个实验。 大多数编译器都足够快运行单线程。在多个不同的源文件上并行运行顺序编译器比让编译器本身并行运行要容易得多。对于垃圾邮件过滤,学习是一个固有的顺序过程。即使是旧机器也可以在一秒钟内学习数百条消息,因此即使是大型语料库也可以在一分钟内学习。同样,训练速度足够快
    3. 我利用并行机器的唯一重要方法是使用并行生成。这是一个巨大的福音,大型构建很容易并行化。 Make 自动完成几乎所有的工作。我能记得的唯一另一件事是使用并行性来计时长时间运行的学生代码,方法是将其移植到一堆实验室机器上,我可以凭良心做到这一点,因为我只破坏了每台机器的一个核心,所以只使用 1 /4 CPU 资源。哦,我写了一个 Lua 脚本,当用 lame 翻录 MP3 文件时将使用所有 4 个内核。该脚本需要大量工作才能正确完成。
    4. 我将忽略数十、数百和数千个内核。我第一次被告知“并行机器即将到来;你必须做好准备”是在 1984 年。当时和今天都是这样,并行编程是高技能专家的领域。唯一改变的是,今天制造商强迫我们为并行硬件付费,无论我们是否愿意。但是硬件付费并不意味着它可以免费使用。编程模型很糟糕,让线程/互斥体模型工作,更不用说表现良好了, 即使硬件是免费的,也是一项昂贵的工作。我希望大多数程序员忽略并行性并安静地处理他们的业务。当一个熟练的专家带着一个平行的品牌或一个伟大的电脑游戏出现时,我会默默地鼓掌并利用他们的努力。如果我想提高自己应用的性能,我将专注于减少内存分配而忽略并行性。
    5. 并行性真的很难。 大多数 域很难并行化。像并行生成这样可广泛重用的异常令人欢欣鼓舞。

    总结(我从一位为领先 CPU 制造商工作的主讲人那里听到):业界支持多核是因为他们无法让机器运行得更快、更热,而且他们不知道如何处理多余的晶体管。现在他们迫切希望找到一种方法来让多核盈利,因为如果他们没有盈利,他们就无法建造下一代晶圆厂生产线。肉汁列车已经结束,我们实际上可能不得不开始关注软件成本。

    许多认真对待并行性的人都忽略了这些玩具 4 核甚至 32 核机器,转而支持具有 128 个或更多处理器的 GPU。我的猜测是,真正的行动将会在那里。

    【讨论】:

    • 我不认为有意忽略并行性是一个好方法,特别是当很明显趋势是越来越多的核心时。此外,编程模型变得越来越容易,例如使用 PLINQ 和英特尔的 Parallel Studio。
    • 多年来,通过忽略并行性,我节省了数百甚至数千小时。平行存在是为了服务我;不是相反。上个月,当我不得不测试 30 个长期运行的学生程序时,我很高兴地使用了分布在 15 台机器上的 30 个内核,但这是一个罕见的事件。
    • 截至 2014 年,这通常仍然是正确的(我是经常使用 Erlang 的怪人之一,不少于)。我编写的大多数客户端软件只需要一个线程即可。正交特征添加通常最适合作为可以与其他/原始程序对话的附加程序。操作系统为我处理这个问题。实际上,在解决商业计算客户端问题的背景下,多核是关于不让 Firefox 或 Flash 或文档查看器阻止会计应用程序或 CAD 程序。服务器端的事情发生了变化,但这不是大多数代码。
    【解决方案2】:

    对于 Web 应用程序来说,这非常非常简单:忽略它。除非您有一些真正需要并行完成的代码,否则您可以简单地编写旧式单线程代码并感到高兴。

    在任何特定时刻,您通常需要处理的请求比您拥有的内核多得多。而且由于每个线程都在自己的线程中处理(甚至是进程,取决于您的技术),这已经在并行工作了。

    您需要注意的唯一地方是访问某种需要同步的全局状态时。将其保持在最低限度,以避免将人为瓶颈引入原本(几乎)完全可扩展的世界。

    所以对我来说,多核基本上归结为以下几点:

    • 我的服务器的“CPU”更少,而每台服务器的内核更多(对我来说差别不大)
    • 相同数量的 CPU 可以支持更多的并发用户
    • 当这似乎是性能瓶颈时,不是 CPU 100% 加载的结果,那么这表明我在某处做了一些糟糕的同步。

    【讨论】:

    • 好答案。长期可扩展性问题如何?如果您开始在芯片上获得比您可以提供的更多的内核,您是否预计必须更改其中的任何内容?对于 1000 个内核,您可能没有所有这些请求的内存带宽。你还能用剩下的内核吗?
    • 在我主要工作的领域(Web 应用程序大多是与偶尔的逻辑绑定的数据库)我不认为我需要在可预见的未来改变这一点(但这样的预测已经知道是错误的),因为它们的主要瓶颈通常是数据库而不是其他。
    • 话虽如此,在某些部分(批处理,罕见的 CPU 绑定部分)编写好的多线程代码肯定会有所帮助,在这里我面临与其他人几乎相同的问题/解决方案。
    • 重要的是要注意 Apache 在内部甚至不使用线程。它只是产生新的进程来处理额外的请求。
    • 实际上,关于 Apache 不使用线程的说法在这一点上已经过时了。
    【解决方案3】:
    1. 目前——说实话,影响不大。我更多地处于“准备阶段”,正在学习使这成为可能的技术和语言特性。
    2. 我没有一个特定的领域,但我遇到过数学(多核必不可少)、数据排序/搜索(多核分治法很有帮助)和多计算机要求等领域(例如,要求备用站的处理能力用于某事)。
    3. 这取决于我使用的语言。显然,在 C# 中,我的双手与尚未准备好的并行扩展实现捆绑在一起,这似乎确实提高了性能,直到您开始将相同的算法与 OpenMP 进行比较(也许不是一个公平的比较)。因此,在 .NET 上,通过一些 forParallel.For 重构等将变得轻松。
      事情变得真正有趣的地方在于 C++,因为您可以压缩性能与 .NET 相比,OpenMP 之类的东西令人震惊。事实上,OpenMP 让我很惊讶,因为我没想到它会如此高效地工作。好吧,我猜它的开发人员已经有很多时间来完善它。我也喜欢它在 Visual Studio 中开箱即用,这与您必须付费的 TBB 不同。
      至于 MPI,我将 PureMPI.net 用于小型家庭项目(我有一个 LAN)玩弄一台机器无法完成的计算。我从未在商业上使用过 MPI,但我知道 MKL 有一些 MPI 优化的功能,对于任何需要它们的人来说可能会很有趣。
    4. 我计划进行“琐碎计算”,即使用额外的内核来预先计算可能需要或可能不需要的结果 - 当然,在 RAM 允许的情况下。我还打算深入研究大多数最终用户的机器目前无法处理的昂贵算法和方法。
    5. 至于没有从并行化中受益的领域……嗯,总能找到一些东西。我担心的一件事是对 .NET 的良好支持,但遗憾的是我已经放弃了能够达到与 C++ 类似的速度的希望。

    【讨论】:

      【解决方案4】:

      我从事医学成像和图像处理工作。

      我们处理多核的方式与处理单核的方式大致相同——我们在编写的应用程序中已经有多个线程,以便获得响应式 UI。

      但是,因为我们现在可以,所以我们正在认真考虑在 CUDA 或 OpenMP 中实现我们的大部分图像处理操作。英特尔编译器为 OpenMP 提供了很多很好的示例代码,并且是比 CUDA 更成熟的产品,并且提供了更大的安装基础,因此我们可能会采用它。

      如果可以的话,对于昂贵的(即超过一秒的)操作,我们倾向于将该操作分叉到另一个进程中。这样,主 UI 仍然是响应式的。如果我们不能,或者移动这么多内存太不方便或太慢,那么操作仍然在一个线程中,然后该操作本身可以产生多个线程。

      对我们来说,关键是确保我们不会遇到并发瓶颈。我们在 .NET 中开发,这意味着 UI 更新必须通过对 UI 的 Invoke 调用来完成,以便让主线程更新 UI。

      也许我很懒,但实际上,当涉及到并行化矩阵求逆之类的事情时,我不想花太多时间来弄清楚这些东西。很多非常聪明的人花了很多时间让这些东西像 nitrous 一样快速,我只是想把他们所做的事情称为它。像 CUDA 这样的东西有一个有趣的图像处理接口(当然,这就是它的定义),但对于那种即插即用的编程来说,它仍然太不成熟。如果我或其他开发人员有很多空闲时间,我们可能会尝试一下。因此,我们将只使用 OpenMP 来加快处理速度(这肯定是未来几个月的开发路线图)。

      【讨论】:

      • 感谢您的精彩回答。您看过最新的 Portland Group Compilers 了吗?现在只是一个预览,但他们已经初步支持使用 CUDA 进行自动加速:pgroup.com/resources/accel.htm
      • 这看起来很有趣。我在Windows上,但是如果编译器可以移植,那我肯定会失败。
      • 我相信它们确实是为 Windows 而来的——PGI 包含在其中:microsoft.com/hpc/en/us/developer-resources.aspx,尽管它只提到了 Fortran。但是 PGI 的网站在这里提到了 Windows 8.0:pgroup.com/support/install.htm#win_info。不过,我还没有尝试过。
      【解决方案5】:

      到目前为止,无非是使用make 进行更高效的编译:

      gmake -j
      

      -j 选项允许不相互依赖的任务并行运行。

      【讨论】:

        【解决方案6】:

        我正在开发 ASP.NET Web 应用程序。在我的代码中直接使用多核的可能性很小,但是通过在负载下产生多个工作线程/进程,IIS 已经很好地扩展了多核/CPU。

        【讨论】:

        • 适用于任何网络环境。
        【解决方案7】:

        我们在使用 F# 的 .NET 4 中的任务并行性方面取得了很大的成功。我们的客户迫切需要多核支持,因为他们不希望自己的 n-1 个内核闲置!

        【讨论】:

          【解决方案8】:

          我从事图像处理。我们通过处理分配给不同线程的切片中的图像,尽可能利用多核。

          【讨论】:

          • 嘿!我现在也遇到了类似的问题,介意看看吗? :) stackoverflow.com/questions/973608/fast-interleaving-of-data
          • 我也为类似的应用程序这样做了。将图像分割成与可用内核数相等的块数。对于双核机器,我通过将图像分成两半并使用一个线程来完成工作,从而获得了 15% 的性能提升。
          • @Andrei - 在“C# 2008 and 2005 Threaded Programming”一书中有一个示例应用程序,它做同样的事情。与您的解决方案进行比较可能是一个很好的参考。
          【解决方案9】:

          我在回答另一个问题时说了其中的一些内容(希望这没问题!):有一个名为 Flow-Based Programming (FBP) 的概念/方法已经存在了 30 多年,并且被用来处理加拿大一家主要银行的大部分批处理。它在 Java 和 C# 中具有基于线程的实现,尽管早期的实现是基于光纤的(C++ 和大型机汇编器)。解决利用多核问题的大多数方法都涉及尝试采用传统的单线程程序并确定哪些部分可以并行运行。 FBP 采用了不同的方法:应用程序从一开始就设计为多个异步运行的“黑盒”组件(想想制造装配线)。由于组件之间的接口是数据流,因此 FBP 本质上与语言无关,因此支持混合语言应用程序和特定领域的语言。以这种方式编写的应用程序被发现比传统的单线程应用程序更易于维护,并且通常花费更少的时间,即使在单核机器上也是如此。

          【讨论】:

            【解决方案10】:

            我的研究生工作是开发用于在嵌入式系统中进行裸机多核工作和教学的概念。

            我还在使用 F# 来提高我的高级多进程语言工具的速度。

            【讨论】:

              【解决方案11】:

              We 创建VivaMP 代码分析器,用于在并行 OpenMP 程序中检测错误。

              VivaMP 是一种类似于 lint 的静态 C/C++ 代码分析器,用于指示基于 OpenMP 技术的并行程序中的错误。 VivaMP 静态分析器大大增加了现有编译器的能力,诊断任何有错误或最终导致此类错误的并行代码。该分析仪已集成到VisualStudio2005/2008开发环境中。

              VivaMP – a tool for OpenMP

              32 OpenMP Traps For C++ Developers

              【讨论】:

                【解决方案12】:

                我相信“自行车是工程师最好的朋友”。

                我的公司提供了一个用于分析的商业工具 并且非常改造 许多计算机语言的大型软件系统。 “大”是指 10-3000 万行代码。 该工具是 DMS 软件再造工具包 (简称DMS)。

                对如此庞大的系统进行分析(甚至转换) 花费很长时间:我们的 C 点分析器 代码在具有 16 Gb RAM 的 x86-64 上需要 90 个 CPU 小时。 工程师希望得到更快的答案。

                因此,我们在PARLANSE 中实施了 DMS, 我们自己设计的并行编程语言, 旨在利用小规模多核共享 记忆系统。

                parlanse 背后的关键思想是: a) 让程序员暴露并行性, b) 让编译器选择它可以实现的部分, c) 将上下文切换保持在绝对最小值。 计算上的静态偏序是 一个容易帮助实现所有 3 个;说起来容易, 相对容易衡量成本, 易于编译器安排计算。 (用这个编写并行快速排序很简单)。

                不幸的是,我们在 1996 年就这样做了 :-( 过去几年终于得到了证明。 我现在可以在 Fry's 以不到 1000 美元的价格买到 8 台核心机器 和 24 核机,价格与小型机差不多 汽车(并且可能会迅速下降)。

                好消息是 DMS 现在已经相当成熟了, 并且有许多关键的内部机制 在 DMS 中利用了这一点,特别是 一整类分析器称为“属性语法”, 我们使用特定领域的语言编写 这不是套话。 DMS 编译这些 将语法属性放入 PARLANSE,然后它们 是并行执行的。我们的 C++ 前端 end 使用属性语法,大约 100K sloc;它被编译成 800K 的并行 SLOC 实际运行可靠的语法代码。

                现在(2009 年 6 月),我们正忙于使 DMS 变得有用,并且 并不总是有足够的时间来利用并行性 好吧。因此,90 小时点分析。 我们正在努力实现并行化,并且 有 10-20 倍加速的合理希望。

                我们相信,从长远来看,利用 SMP 井将使工作站更多 对提出难题的工程师友好。 他们也应该这样做。

                【讨论】:

                  【解决方案13】:

                  我们的域逻辑在很大程度上基于工作流引擎,每个工作流实例都在 ThreadPool 之外运行。

                  这对我们来说已经足够了。

                  【讨论】:

                    【解决方案14】:

                    我现在可以将我的主要操作系统与我的开发分开/安装任何我喜欢的操作系统,使用带有 Virtual PC 或 VMWare 的虚拟化设置。

                    双核意味着一个 CPU 运行我的主机操作系统,另一个运行我的开发操作系统,性能相当不错。

                    【讨论】:

                      【解决方案15】:

                      学习一门函数式编程语言可能会使用多个内核……代价高昂。

                      我认为使用额外的内核并不难。作为 Web 应用程序,有一些琐碎的事情不需要额外注意,因为 Web 服务器会并行运行查询。这些问题是针对长时间运行的算法(长就是你所说的长)。这些需要拆分为不相互依赖的较小域,或同步依赖关系。很多算法都可以做到这一点,但有时需要非常不同的实现(再次成本)。

                      所以,除非您使用命令式编程语言,否则没有灵丹妙药,抱歉。要么您需要熟练的程序员(成本高昂),要么您需要转向其他编程语言(成本高昂)。或者你可能只是运气好(网络)。

                      【讨论】:

                        【解决方案16】:

                        我在 Mac 上使用和编程。 Grand Central Dispatch 为胜利而战。对 Snow Leopard 的 Ars Technica 评论有很多关于多核编程以及人们(或至少是 Apple)将如何使用它的有趣的事情。

                        【讨论】:

                          【解决方案17】:

                          我决定在DEFLATE 算法的实现中利用多个内核。 MArc Adler 在 C 代码中使用 PIGZ(并行 gzip)做了类似的事情。我已经在DotNetZip v1.9 的托管代码库中提供了哲学等价物。这不是 PIGZ 的一个端口,而是一个类似的想法,独立实现。

                          DEFLATE 背后的想法是扫描数据块,查找重复序列,构建一个“字典”,将一个短“代码”映射到每个重复序列,然后发出一个字节流,其中一个的每个实例重复的序列被字典中的“代码”替换。

                          因为构建字典是 CPU 密集型的,所以 DEFLATE 是并行化的完美候选者。我采用了 Map+Reduce 类型的方法,将传入的未压缩字节树划分为一组较小的块(映射),例如每个 64k,然后独立压缩这些块。然后我将生成的块连接在一起(减少)。每个 64k 块在其自己的线程上独立压缩,而不考虑其他块。

                          在双核机器上,这种方法的压缩时间大约是传统串行方法的 54%。在服务器级机器上,有更多可用内核,它可能会提供更好的结果;没有服务器机器,我没有亲自测试过,但人们告诉我它很快。


                          存在与管理多个线程相关的运行时 (cpu) 开销、与每个线程的缓冲区相关的运行时内存开销以及与连接块相关的数据开销。所以这种方法只对更大的字节流有效。在我的测试中,超过 512k,它可以得到回报。在此之下,最好使用串行方法。


                          DotNetZip 作为库提供。我的目标是让这一切变得透明。因此,当缓冲区超过 512kb 时,库会自动使用额外的线程。为了使用线程,应用程序无需执行任何操作。它只是工作,当使用线程时,它神奇地更快。我认为对于应用程序使用的大多数库来说,这是一种合理的方法。


                          如果计算机能够智能地自动和动态地利用可并行算法上的资源,那就太好了,但今天的现实是应用程序设计人员必须明确地编写并行化代码。


                          【讨论】:

                            【解决方案18】:

                            我在 C# 中使用 .Net 线程工作。 您可以将面向对象的封装与线程管理相结合。

                            我读过 Peter 的一些关于 Packt Publishing 新书的帖子,我在 Packt Publishing 网页上找到了以下文章:

                            http://www.packtpub.com/article/simplifying-parallelism-complexity-c-sharp

                            我读过Joe Duffy 的书《Concurrent Programming with Windows》。现在,我正在等待希拉尔的书《C# 2008 和 2005 线程编程》-http://www.amazon.com/2008-2005-Threaded-Programming-Beginners/dp/1847197108/ref=pd_rhf_p_t_2

                            我同意 Szundi “没有灵丹妙药”的观点!

                            【讨论】:

                              【解决方案19】:

                              你说“对于 Web 应用程序来说,这非常非常简单:忽略它。除非你有一些真正需要并行完成的代码,否则你可以简单地编写老式的单线程代码并感到高兴。”

                              我正在使用 Web 应用程序,我确实需要充分利用并行性。 我明白你的意思。但是,我们必须为多核革命做好准备。无视它与无视 90 年代的 GUI 革命是一样的。

                              我们不是还在为 DOS 开发吗?我们必须解决多核问题,否则我们将在多年后死去。

                              【讨论】:

                                【解决方案20】:

                                我认为这种趋势首先会说服一些开发人员,然后他们中的大多数人会看到并行化是一项非常复杂的任务。 我希望一些设计模式能够解决这种复杂性。不是低级别的,而是架构模式,它们很难做错事。

                                例如,我希望消息传递模式越来越流行,因为它本质上是异步的,但您不会考虑死锁或互斥锁等。

                                【讨论】:

                                  【解决方案21】:
                                  1. 这对您的软件路线图有何影响?
                                    它没有。我们(与几乎所有其他)业务相关的应用程序在单核上运行得非常好。只要添加更多内核不会显着降低单线程应用的性能,我们就很高兴

                                  2. ...真实故事...
                                    和其他人一样,并行构建是我们获得的主要好处。不过,Visual Studio 2008 C# 编译器似乎并没有使用多个内核,这真的很糟糕

                                  3. 您如何处理现有代码以利用多核机器
                                    如果我们有一个可以并行化的长时间运行的算法,我们可能会考虑使用 .NET 并行扩展,但这种情况实际发生的可能性很小。最有可能的答案是,一些开发人员会为了兴趣而玩弄它,但其他的不多

                                  4. 您将如何处理数百或数千个内核?
                                    头 -> 沙子。

                                  5. 如果您的领域不容易从并行计算中受益,那么解释原因也很有趣。
                                    客户端应用主要是推送数据,服务端应用主要依赖 SQL Server 来完成繁重的工作

                                  【讨论】:

                                    【解决方案22】:

                                    我正在利用使用 C、PThreads 的多核以及使用 PREEMPT_RT 补丁集的调度程序在带有 Linux 的 OpenVPX 平台上的通信顺序进程的自制实现。所有这些加起来几乎 100% 跨多个操作系统实例的 CPU 使用率,没有 CPU 时间用于 OpenVPX 机箱中的处理器卡之间的数据交换,而且延迟也非常低。还使用 sFPDP 将多个 OpenVPX 机箱连接到一台机器中。我没有使用 Xeon 的内部 DMA 来缓解 CPU 内部的内存压力(DMA 仍然以 CPU 内核为代价使用内存带宽)。相反,我们将数据留在原处并以 CSP 方式传递它的所有权(因此与 .NET 的任务并行数据流库的理念不同)。

                                    1) 软件路线图 - 我们面临着最大限度地利用空间和可用功率的压力。充分利用最新硬件至关重要

                                    2) 软件领域 - 有效的科学计算

                                    3) 我们对现有代码做了什么?不断地将其拆分并在线程之间重新分配部分,以便每个内核在不破坏实时要求的情况下尽其所能。新硬件意味着大量的重新思考(更快的内核可以在给定的时间内做更多的事情,不希望它们被充分利用)。不像听起来那么糟糕——核心程序非常模块化,因此很容易组装成线程大小的块。尽管我们计划从 Linux 中控制线程亲和性,但我们还没有设法通过这样做来获得显着的额外性能。 Linux 非常擅长在或多或少相同的地方获取数据和代码。

                                    4) 实际上已经存在 - 整台机器已经增加了数千个内核

                                    5) 并行计算是必不可少的——它是一个 MISD 系统。

                                    如果这听起来像很多工作,那就是。有些工作需要全力以赴,充分利用可用的硬件,并避开几乎所有高水平的东西。我们发现总机器性能是 CPU 内存带宽的函数,而不是 CPU 核心速度、L1/L2/L3 缓存大小。

                                    【讨论】:

                                      猜你喜欢
                                      • 1970-01-01
                                      • 2020-12-14
                                      • 2019-05-12
                                      • 1970-01-01
                                      • 2015-12-17
                                      • 2012-07-23
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多