pad*_*pad 28 parallel-processing f# haskell functional-programming
功能编程具有不可变的数据结构,并且没有副作用,这些本质上适用于并行编程.我研究了如何在函数式语言中利用多核计算,并针对某些数值应用程序设定生产代码.
F#背后有微软,它的并行结构如PLINQ,TPL,Async Workflow已被充分记录并显示出一些潜力.然而,关于Haskell中的并行性的研究目前非常活跃,并且它具有许多F#尚未支持的优秀特性:
我的问题是我应该选择哪种语言进行功能并行?如果选择了F#,是否有任何指针可以构建他们目前在Haskell中拥有的内容?
更新:
我选择了Simon的答案,因为它带来了关于垃圾收集器,内存分配和缓存未命中的一些很好的讨论.我会坚持使用F#,我认为这些答案对我学习功能并行是有帮助的.
Sim*_*low 51
如果您考虑的代码类型大量分配内存,那么您可能会发现GHC垃圾收集器比.NET垃圾收集器更好地扩展.有一些anedcodal证据表明,当多个线程大量分配时,.NET GC会成为瓶颈,这也是大多数Java收集器中的一个棘手问题.另一方面,我们已经非常注意在GHC垃圾收集器中实现良好的局部性和可伸缩性 - 主要是因为我们别无选择,大多数惯用的Haskell代码无论如何都会分配很多.我有基准,分配像疯了一样,并保持超过24核心的扩展.
在Haskell中请注意,您可以从类型系统中获得确定性的保证,而F#中没有这种确定性.
你提到了Data Parallel Haskell:这里是一个警示性的注释,虽然DPH团队期望即将发布的GHC 7.2.1版本具有稳定的DPH实现,但目前还没有为生产使用做好准备.
Tom*_*cek 22
首先,我同意其他人没有客观的答案.
但是,我认为功能并行的想法有点高估了.当然,您可以轻松地在程序中找到数据依赖项,如果您正在处理大量数据,则可以使用一些数据并行库来轻松安全地并行化它.但是,即使在C#(使用TPL和PLINQ)中也可以这样做,如果你对你所写的内容有点小心的话.
问题是,大多数程序不需要并行化,因为它们根本没有做足够的CPU密集型工作.例如,F#async解决了(我认为)启用异步I/O的更重要问题,这是连接应用程序中大多数"挂起"的原因.我认为Node.js的受欢迎程度非常好地证明了这一重要性.
函数式语言的真正价值在于语言的表达性 - 您可以轻松定义问题的抽象,以更简洁的方式编写代码,更容易理解,推理和测试.你可以在F#和Haskell中得到这个.
回答关于并行性的具体问题 - 我相信F#中并行性支持的状态更稳定(但是,我是F#人).您可以选择async,TPL和(Erlang-inspired)F#代理(它们都是非常稳定的库).在Haskell方面,仍然有很多进化.在最近的工作仅仅是几个星期了.我还发现在具有明确指定评估模型的语言中使用并行性更容易,但这可能仅仅是我个人的偏好.
Jon*_*rsi 21
我会为此投降,但让我成为一个吝啬鬼.
功能语言很棒.它们改变了你对分解问题的看法,并且非常好地映射到某些类型的问题.每个程序员都应该熟悉至少一种函数式编程语言.但是"函数式语言对于并行编程本质上是有益的"可能不是原因所在.
值得注意的是,无疑是有史以来最成功的并行函数语言,Erlang使用完全标准的消息传递来实现其并行性,并且其功能性和并行性之间的联系最多是间接的.
二十五年前,功能语言得到了极大的推动,因为这个论点看起来非常引人注目 - 功能语言似乎很适合当时日益平行的架构.由于语言的副作用自由,编译器和运行时将自动实现并行性. SISAL,甚至可以编译成共享和分布式内存(!)可执行文件,此时开发,就像Haskell一样,也是ML,它是Objective CAML的前身和ML系列中的其他语言.
这只是提供了一些历史观点.对于字面上四分之一个世纪,功能语言倡导者,包括该领域一些最聪明的人,一直在说功能语言在阳光下的日子即将到来,并且它将适用于并行性这是杀手级的应用程序.然而,我们在这里,甚至没有人听说过SISAL; 而且我猜这篇文章的大多数读者都认为Haskell是一种热门的新语言.
当然,很可能现在有了多核考虑因素,事情终于变得非常紧迫,功能语言真的会大放异彩,或者今年将是有一些突破的一年,我甚至无法想象哪一个彻底改变了景观.今年可能与前25年的每一年都不同.但它也可能不会.
现在存在的庞大,绝大多数并行和并发代码,以及可预见的未来,都不是用函数式语言编写的.如果您正在寻求了解并行性,请务必探索F#,Haskell等中可用的机制; 但是不要局限于那些,我只是说.
ild*_*arn 12
简单的答案是,因为两种语言都支持并行性和并发性,所以这不应该成为决定使用哪种语言的因素.也就是说,有一个更大的因素需要考虑这样的决定.
Jon*_*rop 10
功能编程具有不可变的数据结构,并且没有副作用,这些本质上适用于并行编程.
这是一种常见的误解.并行性完全取决于性能和纯度会降低性能.如果你的目标是获得不错的表现,那么纯功能编程并不是一个好的起点.一般而言,纯度意味着更多的分配和更糟糕的局部性.特别是,纯粹的功能数据结构用树替换数组,并且会导致更多的分配并给垃圾收集器带来更多的负担.
例如,在Haskell中测量优雅的纯函数"quicksort"的性能.最后我检查过,它比我机器上的传统命令解决方案慢了几千倍.
此外,没有人设法在Haskell中实现有效的字典数据结构(纯粹或不纯)或高效的纯函数排序,没有人想出如何编写渐近有效的持久不相交集数据结构,并且没有已知的方法来实现其他基本数据结构,如纯函数弱字典!
此外,虽然理论上可以在Haskell中编写不纯的代码,但GC会以牺牲突变性能为代价对纯代码进行大量优化.例如,GHC的哈希表仍然比.NET慢26倍.从历史上看,突变的性能在Haskell中被认为是如此不重要,以至于写一个指向数组的指针是GHC中的O(n)操作已有五年了.
我研究了如何在函数式语言中利用多核计算,并针对某些数值应用程序设定生产代码.
我找到的最好的方法是学习如何在命令式样式(特别是研究Cilk)中编写适合多核的并行程序,然后使用一流函数和尾部调用消除将代码分解为不纯的函数样式.
这意味着缓存不经意的数据结构和算法.在Haskell中没有人这样做过.事实上,迄今为止在并行Haskell上发表的研究都没有提到缓存复杂性的基本概念.此外,尽管众所周知非严格(即懒惰)评估使得空间消耗不可预测,但是尚未普遍认识到同样的问题使得可扩展性在多核上变得非常不可预测.
F#背后有微软,它的并行结构如PLINQ,TPL,Async Workflow已被充分记录并显示出一些潜力.
它们远远超出潜力.成千上万的商业应用建立在这些工业强度基础之上.
然而,关于Haskell中的并行性的研究目前非常活跃,并且它具有许多尚未被F#支持的优秀特性:
为什么你认为它们是"很好的功能"?
我建议阅读Simon Marlow的最新论文:
"...实践经验和调查的结合使我们得出结论,这种方法并非没有缺点.简而言之,问题是:实现并行性par要求程序员理解最多的语言的操作属性实施 - 定义(最糟糕的是未定义).这使得par难以使用,并且陷阱很多 - 新用户的失败率很高......"
我的问题是我应该选择哪种语言进行功能并行?
我建议不要使用并行的纯功能代码进行生产,因为它是一个完整的外卡.假设你很高兴为了获得竞争性的表现而牺牲一些纯度,我会使用并推荐F#.
Haskell的纯度意味着它在并行处理和并发之间做出了明确的区分.
如果您希望通过在多个内核上分配工作来加速大数据处理应用程序,那么您需要并行处理,这意味着"par"及其衍生产品.通过仔细使用这些结构,您可以让您的CPU密集型纯函数在N个内核上运行N倍,同时确保您没有更改原始代码的含义或在程序中引入非确定性.
另一方面,如果您希望您的程序与外部世界中的多个实体交互,交错来自不同实体的通信但仍然具有一定程度的共享资源,那么您需要并发,这意味着使用"fork"和STM的某些组合和TVars.STM为您提供了很好的事务语义,这对于消除竞争条件和其他并发性恶作剧有很大帮助.您需要注意碰撞频率和重试率.
| 归档时间: |
|
| 查看次数: |
7255 次 |
| 最近记录: |