功能并行的编程语言:F#vs Haskell

时间:2011-03-30 21:56:32

标签: haskell f# functional-programming parallel-processing

函数式编程具有不可变的数据结构,没有副作用,本质上适用于并行编程。我研究了如何在函数式语言中利用多核计算,并针对某些数值应用程序设定生产代码。

F#背后有微软,其并行结构如PLINQTPLAsync Workflow已被充分记录并显示出一些潜力。然而,关于Haskell并行性的研究目前非常活跃,并且它具有很多很好的功能,而这些功能还没有得到F#的支持:

我的问题是我应该选择哪种语言进行功能并行?如果选择F#,是否有任何指针可以构建他们目前在Haskell中拥有的内容?

更新

我选择了Simon的答案,因为它带来了关于垃圾收集器,内存分配和缓存未命中的一些很好的讨论。我会坚持使用F#,我认为这些答案对我学习功能并行是有帮助的。

7 个答案:

答案 0 :(得分:50)

如果你想到的代码类型大量分配内存,那么你可能会发现GHC垃圾收集器比.NET垃圾收集器更好地扩展。有一些anedcodal evidence,当多个线程分配很多时,.NET GC会成为瓶颈,而且这也是大多数Java收集器的thorn in the side。另一方面,我们已经非常注意在GHC垃圾收集器中实现良好的局部性和可伸缩性 - 主要是因为我们别无选择,大多数惯用的Haskell代码无论如何都会分配很多。我的基准测试分配得像疯了一样,并且可以扩展到超过24个内核。

在Haskell中请注意,您可以从类型系统中获得确定性的保证,而这是F#中没有的。

你提到了Data Parallel Haskell:这里有一个注意事项,它目前尚未准备好用于生产,尽管DPH团队期望即将发布的GHC 7.2.1版本将具有稳定的DPH实现。

答案 1 :(得分:21)

首先,我同意其他人没有客观的答案。

但是,我认为功能并行的想法有点高估了。当然,您可以轻松地在程序中找到数据依赖项,如果您正在处理大量数据,则可以使用一些数据并行库来轻松安全地并行化它。但是,即使在C#(使用TPL和PLINQ)中也可以这样做,如果你对你所写的内容有点小心。

问题是,大多数程序不需要并行化,因为它们根本没有做足够的CPU密集型工作。例如,F#async解决了(我认为)启用异步I / O的更重要问题,这是连接应用程序中大多数“挂起”的原因。我认为Node.js的普及很好地证明了这一重要性。

函数式语言的真正价值在于语言的表达能力 - 您可以轻松定义问题的抽象,以更简洁的方式编写代码,更容易理解,推理和测试。你可以在F#和Haskell中得到这个。

回答关于并行性的具体问题 - 我认为F#中并行支持的状态更稳定(但是,我是F#人)。您可以选择async,TPL和(Erlang-inspired)F#代理(它们都是非常稳定的库)。在Haskell方面,仍然有很多进化。 most recent work只有几个星期的历史。我还发现在具有明确指定评估模型的语言中使用并行性更容易,但这可能只是我个人的偏好。

答案 2 :(得分:20)

我会为此而投票,但让我成为一个吝啬鬼。

功能语言很棒。它们改变了你对分解问题的看法,并且非常好地映射到某些类型的问题。每个程序员都应该熟悉至少一种函数式编程语言。但是“函数式语言对并行编程本质上是有益的”可能不是原因。

值得注意的是,无疑是有史以来最成功的并行功能语言,Erlang使用完全标准的消息传递来实现其并行性,并且其功能性和并行性之间的联系最多是间接的。< / p>

二十五年前,人们对功能语言进行了巨大的推动,因为这个论点看起来非常引人注目 - 功能语言似乎很适合当时日益平行的架构。由于语言的副作用自由,编译器和运行时将自动实现并行性。 SISAL,甚至可以被编译成共享和分布式内存(!)可执行文件,这个时候就像Haskell一样,就像ML,它是Objective CAML的前身和ML中的其他语言一样。家族。

这只是提供了一些历史观点。对于字面上四分之一个世纪,功能语言倡导者,包括该领域一些最聪明的人,一直在说功能语言在阳光下的日子即将到来,并且它将适用于并行性这是杀手级的应用程序。然而,我们在这里,甚至没有人听说过SISAL;而且我猜这篇文章的大多数读者都认为Haskell是一种热门的新语言。

当然,很可能现在有了多核考虑因素,事情终于变得如此迫切,以至于功能语言真的会大放异彩,或者说今年将会有一些突破我无法想象的那一年完全改变了景观。今年可能与前25年的每一年都不同。但它也可能不会。

现在存在的庞大,绝大多数并行和并发代码,以及可预见的未来,都不是用函数式语言编写的。如果您正在寻求了解并行性,请务必探索F#,Haskell等中可用的机制;但是不要局限于那些,我只是说。

答案 3 :(得分:12)

简单的答案是,因为这两种语言都支持并行性和并发性,所以这不应该成为决定使用哪种语言的因素。即,像这样的决定需要考虑个更大的因素。

答案 4 :(得分:9)

  

函数式编程具有不可变的数据结构,没有副作用,本质上适用于并行编程。

这是一种常见的误解。并行性完全取决于性能和纯度会降低性能。如果你的目标是获得不错的表现,那么纯功能编程并不是一个好的起点。一般而言,纯度意味着更多的分配和更糟糕的局部性。特别是,纯粹的功能数据结构用树替换数组,并且会导致更多的分配并给垃圾收集器带来更多的负担。

例如,衡量the elegant purely functional "quicksort" in Haskell的效果。最后我检查过,它比我机器上传统的命令式解决方案慢了几千倍。

此外,没有人设法在Haskell和nobody has figured out how to write an asymptotically efficient persistent disjoint set data structure中实现高效的字典数据结构(纯粹的或不纯的)或高效的纯函数排序,并且没有已知的方法来实现纯粹的其他基本数据结构功能弱的词典!

此外,虽然理论上可以在Haskell中编写不纯的代码,但GC会以牺牲突变性能为代价对纯代码进行大量优化。例如,GHC's hash table is still 26× slower than .NET's。历史上,the performance of mutation was considered so unimportant in Haskell that writing a single pointer to an array was an O(n) operation in GHC for five years

  

我研究如何在函数式语言中利用多核计算,并针对某些数值应用程序设定生产代码。

我找到的最好方法是学习如何在命令式样式(特别是研究Cilk)中编写适合多核的并行程序,然后使用一等函数和尾部调用消除将代码分解为不纯的功能样式。

这意味着缓存不经意的数据结构和算法。在Haskell中没有人这样做过。的确,none of the research published on parallel Haskell to-date has even mentioned the essential concept of cache complexity。此外,虽然众所周知非严格(又称懒惰)评估会使空间消耗无法预测,但尚未广泛认识到同样的问题会导致可扩展性在多核上极不可预测。

  

F#背后有微软,它的并行结构如PLINQ,TPL,Async Workflow已被充分记录并显示出一定的潜力。

他们远远超出潜力。成千上万的商业应用建立在这些工业强度的基础之上。

  

然而,关于Haskell中的并行性的研究目前非常活跃,并且它具有很多很好的功能,但还没有得到F#的支持:

为什么你认为它们是“很好的功能”?

我建议您阅读Simon Marlow's latest paper

“......实践经验和调查的结合使我们得出结论,这种方法并非没有缺点。简而言之,问题是这样:与par实现并行性要求程序员理解操作最好实现的语言的属性 - 定义(最糟糕的是未定义)。这使par难以使用,并且陷阱很多 - 新用户的失败率很高......“

  

我的问题是我应该选择哪种语言进行功能并行?

我建议不要使用并行纯功能代码进行生产,因为它是一张完整的外卡。假设你很高兴为了获得竞争性而牺牲一些纯度,我会使用并推荐F#。

答案 5 :(得分:8)

没有客观的答案。对于Haskell来说,有大量积极的工作,没有“一刀切”的方法。相反,在Haskell中,提供了许多用于实现并行性的不同工具。 What's the status of multicore programming in Haskell?

答案 6 :(得分:6)

Haskell的纯度意味着它在并行处理和并发之间做出了明确的区分。

  • 如果您希望通过在多个内核上分配工作来加速大型数据处理应用程序,那么您需要并行处理,这意味着“par”及其衍生产品。通过仔细使用这些结构,您可以让您的CPU密集型纯函数在N个内核上运行N倍,同时确保您没有更改原始代码的含义或在程序中引入非确定性。

  • 另一方面,如果您希望您的程序与外部世界中的多个实体交互,交错来自不同实体的通信但仍然具有一定程度的共享资源,那么您需要并发,这意味着使用“fork”以及STM和TVars的某种组合。 STM为您提供了很好的事务语义,这对于消除竞争条件和其他并发性恶作剧有很大帮助。你需要注意碰撞频率和重试率。