我们今天推荐哪种并行编程模型来利用明天的多核处理器?

时间:2020-03-05 18:57:56  来源:igfitidea点击:

如果我们今天从头开始编写一个新应用程序,并希望将其扩展到明天可以使用的所有内核,那么我们将选择哪种并行编程模型/系统/语言/库?为什么?

我对这些方面的答案特别感兴趣:

  • 程序员的生产率/易用性(凡人都能成功使用吗?)
  • 目标应用程序域((不)擅长什么问题?)
  • 性能(如何扩展到哪种硬件上?)

我刻意在模糊应用程序的性质,以期获得对各种应用程序有用的良好通用答案。

解决方案

回答

对于.NET应用程序,我选择" .NET并行扩展(PLINQ)",它非常易于使用,并允许我在几分钟内并行化现有代码。

  • 简单易学
  • 用于对大型对象执行复杂的操作,因此我无法对其他应用程序发表评论
  • 支持任务和指导
  • 未来几年应该得到支持,但是谁能确定呢?
  • CTP版本存在一些性能问题,但看起来非常有希望。

Mono可能会获得对PLINQ的支持,因此它也可能是跨平台的解决方案。

回答

Qt并发为多核提供了MapReduce的实现,这确实很容易使用。这是multiOS。

回答

我会使用Java的可移植性,因此将来的处理器不会成为问题。我还将使用接口,逻辑和数据(更像是3层Web应用程序)分隔层的代码编写应用程序,并将标准互斥例程作为库(较少并行代码的调试)。请记住,Web服务器可以很好地扩展到许多处理器,并且是通往多核的最轻松的途径。或者看一看旧的Connection Machine模型,其中将虚拟处理器绑定到数据。

回答

mapreduce / hadoop范例是有用的,并且相关。特别是对于那些习惯于像perl之类的语言的人来说,在数组上进行映射并在每个元素上执行某些操作的想法应该自然而然地出现,而mapreduce / hadoop只是将其带入下一阶段,并说没有理由数组的每个元素都需要在同一台机器上处理。

从某种意义上说,这是经过更多测试的结果,因为Google正在使用mapreduce,并且很多人都在使用hadoop,并且表明它非常适合在网络上跨多台机器扩展应用程序。而且,如果我们可以扩展整个网络中的多台计算机,则可以扩展一台计算机中的多个内核。

回答

我敢打赌用promise传递事件循环,就像在Twisted,E,AmbientTalk等系统中实现的那样。它们保留以与非并行/并行应用程序相同的执行模型假设编写代码的能力,但可以扩展到分布式和并行系统。 (这就是为什么我从事Ecru的原因。)

回答

看看Erlang。 Google,并观看各种演示和视频。我尊重的许多程序员和架构师都对它的可伸缩性很满意。我们在工作很忙的地方使用它...

回答

对于繁重的计算等,像Haskell这样的纯函数式语言很容易并行化,而无需程序员费力。除了学习Haskell,就是这样。

但是,我不认为这是(不久的将来)的方式,这仅仅是因为太多的程序员已经习惯了命令式编程范例。

回答

如果问题域允许,请尝试考虑不共享模型。我们在进程和线程之间共享的资源越少,设计复杂的并发模型的工作就越少。

回答

我真正喜欢的两个解决方案是联接演算(JoCaml,Polyphonic C#,C)和角色模型(Erlang,Scala,E,Io)。

我对软件事务性内存没有特别的印象。感觉就像只是允许线程保留更长的时间,即使它们早在几十年前就已经死掉了。但是,它确实具有三个主要优点:

  • 人们了解数据库中的交易
  • 已经有关于事务性RAM硬件的讨论
  • 就像我们所有人都希望它们消失一样,线程可能将在接下来的几十年中成为主导的并发模型,这可能是令人遗憾的。 STM可以显着减轻疼痛。

回答

多核编程实际上可能需要多个范例。当前的一些竞争者是:

  • MapReduce。这在将问题轻松分解为并行块的情况下效果很好。
  • 嵌套数据并行性。这类似于MapReduce,但实际上支持问题的递归分解,即使递归块的大小不规则也是如此。希望NDP在运行在大规模并行但功能有限的硬件(例如GPU)上的纯功能语言中大获成功。
  • 软件事务性内存。如果我们需要传统线程,则STM使它们可以承受。我们在关键部分会损失50%的性能,但是我们可以轻松地将复杂的锁定方案扩展到100个处理器。但是,这不适用于分布式系统。
  • 带有消息传递的并行对象线程。这个非常聪明的模型被Erlang使用。每个"对象"都变成一个轻量级线程,并且对象通过异步消息和模式匹配进行通信。基本上是真正的并行OO。这在一些实际应用中取得了很好的成功,并且对于不可靠的分布式系统也非常有效。

这些范例中的某些范例可为我们提供最佳性能,但仅在问题完全分解的情况下才有效。其他人则牺牲了一些性能,但允许使用更多种算法。我怀疑以上各项的某种组合最终将成为标准工具箱。

回答

如前所述,纯功能语言本质上是可并行化的。但是,命令式语言对于许多人来说更加直观,并且我们对命令式遗留代码深深地根深蒂固。根本问题是纯功能语言明确表示副作用,而副作用则按命令的顺序在命令式语言中隐式表示。

我相信声明式表达副作用的技术(例如在面向对象的框架中)将允许编译器将命令式语句分解为它们的功能关系。然后,这应该允许代码以与纯功能代码几乎相同的方式自动并行化。

当然,就像今天仍然需要用汇编语言编写某些性能关键的代码一样,明天仍然有必要编写性能关键的显式并行代码。但是,我概述的技术应该可以帮助开发人员以最少的精力自动利用多核体系结构。

回答

kamaelia是一个python框架,用于构建具有许多通信流程的应用程序。

http://www.kamaelia.org/cat-trans-medium.png Kamaelia - Concurrency made useful, fun
  
  In Kamaelia you build systems from simple components that talk to each other. This speeds development, massively aids maintenance and also means you build naturally concurrent software. It's intended to be accessible by any developer, including novices. It also makes it fun :)  
  
  What sort of systems? Network servers, clients, desktop applications, pygame based games, transcode systems and pipelines, digital TV systems, spam eradicators, teaching tools, and a fair amount more :)

另请参阅问题多核和并发语言,库和开发技术

回答

另请参阅问题多核和并发语言,库和开发技术

回答

Erlang是更"成熟的解决方案",并且是可移植的开放源代码。我摆弄了Polyphonic C,我不知道每天在其中进行编程将是什么。

在Google和Google事务存储环境下,几乎每种语言/操作系统都有库和扩展名。这是MS的一种有趣的方法。

回答

我很惊讶没有人建议使用MPI(消息传递接口)。当设计用于分布式内存时,具有必要且频繁的全局耦合(解决具有数十亿未知数的线性和非线性方程)的MPI程序已显示可扩展至200k内核。

回答

这个问题似乎一直以不同的措辞出现,也许StackOverflow中存在不同的选区。基于流的编程(FBP)是一种概念/方法,已经存在了30多年,并且已在加拿大一家大型银行中用于处理大多数批处理。它具有Java和C#的基于线程的实现,尽管较早的实现是基于光纤的(C ++和大型机汇编器是银行中使用的一种)。利用多核问题的大多数方法都涉及尝试采用常规的单线程程序并弄清楚哪些部分可以并行运行。 FBP采用了不同的方法:从一开始就针对多个异步运行的"黑匣子"组件(例如生产装配线)设计了该应用程序。由于组件之间的接口是数据流,因此FBP本质上与语言无关,因此支持混合语言应用程序和特定于域的语言。出于相同的原因,副作用被最小化。它也可以描述为"不共享"模型和MOM(面向消息的中间件)。 MapReduce似乎是FBP的特例。 FBP与Erlang的不同之处主要在于Erlang在许多短寿命线程方面进行操作,因此绿色线程在那里更合适,而FBP使用更少(通常为几十到几百到几百)更长寿命的线程。对于每天使用超过30年的批处理网络,请参阅批处理网络的一部分。有关交互式应用程序的高级设计,请参阅Brokerage应用程序的高级设计。已经发现FBP可以导致更易于维护的应用程序,甚至在单核计算机上也可以缩短运行时间!

回答

具有多个工作人员系统的作业队列(不确定正确的术语消息队列吗?)

为什么?

主要是因为这是一个荒谬的简单概念。我们有一个需要处理的东西的清单,然后是一堆获得工作并对其进行处理的过程。

另外,与原因不同,例如Haskell或者Erlang如此并发/可并行化(?),它完全与语言无关,我们可以使用C或者Python或者任何其他语言(甚至使用Shell脚本)轻松实现这样的系统,而我怀疑bash很快就会获得软件事务性内存或者联接演算。

回答

在过去的十年中,我们一直在使用PARLANSE(一种并行编程语言,具有并发的显式部分顺序规范)来实现可扩展的程序分析和转换系统(DMS Software Reengineering Toolkit),该系统主要执行符号计算而不是数值计算。 PARLANSE是一种类似于C的编译语言,具有传统的标量数据类型字符,整数,浮点数,动态数据类型字符串和数组,复合数据类型结构和并集以及词法作用域函数。虽然大多数语言是普通语言(操作数上的算术表达式,if-then-else语句,do循环,函数调用),但并行性却不是。并行性是通过在代码块上定义"先于"关系来表示的(例如,a在b之前,a在c之前,d在c之前)
写为

(|;  a  (... a's computation)
     (<< a) b ( ... b's computation ... )
     (<< a) c ( ....c's computation ...)
     (>> c) d ( ... d's computation...)
)|;

<<和>>运算符指的是"时间顺序"。 PARLANSE编译器可以看到这些并行计算,并预分配了计算所需的所有结构
晶粒a,b,c,d,并生成自定义代码来启动/停止每个晶粒,从而最小化了启动和停止这些平行晶粒的开销。

请参阅此链接,以并行迭代加深搜索以找到15难题的最佳解决方案,这是8难题的4x4大兄弟。它仅将潜在的并行用作并行结构(|| a b c d),该结构表示对计算a b c d的执行没有部分顺序约束,但是它也使用推测并且异步中止了找不到解决方案的任务。很少的代码就包含了很多想法。

PARLANSE在多核PC上运行。一个大型的PARLANSE程序(我们已经建立了许多带有100万以上行的程序)将具有成千上万个这样的部分订单,其中一些调用函数包含其他部分。
到目前为止,多达8个CPU取得了不错的结果,多达16个CPU的收益不高,我们仍在调整系统。 (我们认为当前PC上大量内核的一个真正问题是内存带宽:内存子系统中的16个内核构成了巨大的带宽需求)。

大多数其他语言都没有公开并行性,因此很难找到,并且运行时系统为使用通用调度原语来调度计算粒度付出了高昂的代价。我们认为这是灾难的根源,或者至少是由于阿姆达尔定律而导致性能不佳的原因:与工作相比,如果计划谷物的机器指令数量很大,那么我们就无法高效。 OTOH,如果我们坚持使用带有许多机器指令的计算粒度来保持较低的调度成本,那么我们将找不到独立的计算粒度,因此就没有任何有用的并行性来调度。因此,PARLANSE背后的关键思想是使调度晶粒的成本最小化,以使晶粒变小,从而可以在真实代码中找到许多晶粒。这种权衡的见解来自纯数据流范例的绝对失败,该失败以微小的并行块(例如,add运算符)并行完成所有操作。

我们已经对此进行了十年的研究。很难做到这一点。我没有看到那些尚未构建并行语言并在此时间范围内使用/调整它们的人如何有很大的机会构建有效的并行系统。

回答

我非常喜欢Clojure选择的模型。 Clojure使用了不可变数据结构和软件事务存储的组合。

不变的数据结构是永远不变的。可以使用修改后的数据来创建结构的新版本,但是,如果我们有指向数据结构的"指针",则它永远不会在身后改变。这很好,因为我们可以访问该数据而不必担心并发问题。

在这些答案的其他地方讨论了软件事务存储,但是可以说这是一种机制,多个线程都可以对某些数据执行操作,如果它们发生冲突,则其中一个线程会回滚以重试。当存在碰撞危险但不太可能发生碰撞时,这可以加快速度。

有作者Rich Hickey的视频,其中有很多细节。

回答

值得一提的路径可能是OpenCL,它提供了一种在异构计算资源之间分配某些类型的计算负载的方法,即相同的代码将在多核CPU以及商用GPU上运行。 ATI最近发布了完全这样的工具链。 NVidia的CUDA工具链是类似的,尽管有更多限制。看来Nvidia正在开发OpenCL sdk

应当指出,这在工作负载不是数据并行性质的情况下可能无济于事,例如,对于典型的事务处理而言,它无济于事。 OpenCL主要面向数学密集型的计算类型,例如科学/工程仿真或者财务建模。

回答

If you were writing a new application from scratch today, and wanted it to scale to all the cores you could throw at it tomorrow, what parallel programming model/system/language/library would you choose?

也许今天最广泛应用的是Cilk式任务队列(现在在.NET 4中可用)。它们非常适用于可以解决问题的问题,这些问题可以通过使用子任务的可预测复杂度进行分而治之(例如,在函数参数的复杂度众所周知的数组上并行执行" map"和" reduce"以及像快速排序这样的算法),并且涵盖许多实际问题。

而且,这仅适用于当今多核之类的共享内存架构。尽管我不相信这种基本架构会在不久的将来消失,但我确实相信它必须在某个时候与分布式并行机制结合起来。这将以多核CPU上的多核群集的形式在多核之间传递消息,或者以核之间具有可预测的通信时间的层次结构的形式出现。这些将要求完全不同的编程模型来获得最大的效率,我不相信他们有多少。