Haskell、Scala、Clojure,选择哪个用于高性能模式匹配和并发?

45

我最近开始接触函数式编程,阅读了很多关于FP并发执行和性能优势的博客和文章。我的应用程序需要注入基于状态的数据到另一个子系统中,其中时间非常关键(每秒接近200万个交易)。我有几个这样的子系统需要进行测试。

我认真考虑使用FP来实现并行计算,并想采取正确的方法。许多SO上的帖子都谈论了Scala、Haskell和Clojure在语言结构、库和JVM支持方面的优缺点。从语言的角度来看,只要它能帮助我实现结果,我可以学习任何一种语言。

某些帖子推荐Haskell的模式匹配和语言简单性,基于JVM的FP语言在使用现有Java库方面具有巨大优势。JaneStreet是OCaml的忠实支持者,但我确实不确定是否有开发者支持和帮助论坛。

如果有人处理过如此大的数据,请分享你的经验。


你可能也会对这个Scala与Clojure速度比较的测试感兴趣:https://dev59.com/rWgu5IYBdhLWcg3wBym1 - om-nom-nom
2个回答

54

你想要速度还是简便?

如果你想要速度,即使你使用FP原则来帮助确保正确性,你应该使用C ++。由于时间非常关键,软(和硬,如果需要)实时编程的支持将非常重要。您可以确定何时以及何时恢复内存,并仅花费所需时间。

你提到的三种语言都比接近最优手动调整的C ++慢〜2-3倍, 而且只有在使用相当传统的命令式方式时才会慢。它们都使用垃圾收集,这将在您的事务中引入不受控制的随机延迟。

话虽如此,用C++实现这个功能需要很多工作才能做到完美。应用FP原则需要更多的样板文件(即使在C ++ 11中),大多数库默认情况下是可变的。(编辑:Rust正在成为一个好的选择,但本答案范围无法对Rust进行足够详细的描述。)

也许你没有时间并且可以在其他规格上缩减。如果关键不是时间而是吞吐量,例如,那么你可能希望使用Scala而不是Clojure(请参见计算机语言基准测试,截至本文撰写时,Scala在每个基准测试中都获胜,并且在几乎每种情况下具有较小的代码大小(编辑:CLBG在这方面已经没有帮助了,但您可以在Web Archive上找到支持这些陈述的存档));OCaml和Haskell应该出于其他原因进行选择(类似的基准测试分数,但它们具有不同的语法和互操作性等)。
就最佳并发支持系统而言,Haskell、Clojure和Scala都很好,而OCaml则有点不足。
这基本上缩小了选择范围,可以选择Haskell和Scala。你需要使用Java库吗?选择Scala。你需要使用C库吗?可能是Haskell。如果两者都不需要,那么你可以根据自己的风格喜好选择其中任何一个,而不必过分担心选择错误会使生活变得更加艰难。

12
你能否在“比C++慢2-3倍”的语句中添加一个参考文献?谢谢。 - Edmondo
9
相较于以函数式编程风格编写时,C语言与C++相比不仅速度上没有额外的优势,而且还存在更大的语法负担。唯一选择C语言的原因是在某些平台上没有C++编译器可用(如嵌入式系统、FPGA代码生成器等)。但我认为这不是此处的情况。 - Rex Kerr
2
@Edmondo1984 - 我想你误解了我的意思。我认为谷歌文档并不好,我不希望包含链接,因为我认为这会误导人们或浪费他们的时间,因为他们仔细阅读后最终意识到它并不好。(我不认为他们打算让它变得很好--只是有点有趣,然后人们想要读取比作者意图更多的内容。) - Rex Kerr
2
现在,Rust可能是一个不错的选择。它具有像Haskell一样的模式匹配,并且比C ++更好地支持FP,但在基准测试中的表现与C ++相当。 - saolof
2
@saolof - 同意。 Rust 是一个值得探索的替代选择。 - Rex Kerr
显示剩余5条评论

28

我用Clojure实现了这个功能,它有以下几个优点:

  • 在JVM上运行可以方便地使用库,这是它的巨大优势。因此,我们需要轻松访问Java生态系统,并与基于JVM的工具(如Maven build)集成,这有效地排除了Haskell和Ocaml。
  • 如果需要紧密优化内部循环,可以切换到纯Java。我们对一些自定义代码处理大型double[]数组进行了优化,但99%的时间Clojure就能满足你的性能需求。请参见http://www.infoq.com/presentations/Why-Prismatic-Goes-Faster-With-Clojure以获取有关如何使Clojure快速运行的示例(相当技术性的视频,需要一些先前的知识!)。一旦开始计算利用多个核心的便利性,Clojure在性能上就非常有竞争力。
  • Clojure具有非常好的多核并发支持,这对于管理并发任务非常有用。请参见http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey
  • REPL为数据测试和探索工作提供了很好的环境。
  • Clojure是“惰性”的,适合处理大于内存的数据集(假设你小心不要尝试一次将整个数据集强制加载到内存中)。在这样的环境中还有一些不错的库可用,其中最显著的是StormAleph。对于你来说,Storm可能特别有趣,因为它是为实时处理大量事件而设计的分布式系统。

我没有使用其他语言的太多经验,但根据我对Haskell和Scala的一些实际经验的印象:

  • Haskell非常适合关注纯度和具有静态类型的严格函数编程。静态类型可以是正确性的强有力保证,因此可能适用于高度算法工作。个人而言,我认为纯函数式编程有点太死板了-有许多时候可变状态很有用,我认为Clojure在这方面有稍微更好的平衡(通过允许受控的可变性通过管理参考)。
  • Scala是一种伟大的语言,并与Clojure共享使用JVM的优势。对我而言,Scala更像是一个带有功能特性和非常出色的类型系统的“更好的Java”。它与Clojure相比不那么具有范式转变。缺点是类型系统可能会变得相当复杂/令人困惑。

总的来说,我认为你可以对其中任何一种感到满意。最终可能会取决于您对JVM的重视程度以及您对类型系统的看法。


6
你提出的5个论点中有4个同样适用于Scala(最后一个除外——Clojure是惰性求值的)。 - om-nom-nom
是的,同意,我真的很喜欢Scala,只是没有像用其他语言那样频繁地使用它。两个语言都很棒。不过可以争论的是,在Scala中也可以通过一些努力实现惰性行为,只是没有像Clojure那样内置到同样的程度。 - mikera
10
许多(大多数)人认为Scala的类型系统是一种优点而非缺点。 - ziggystar
4
虽然Clojure使得处理惰性序列变得容易,但是称一种语言为“惰性”的通常指的是它的求值策略。在这方面,Haskell比Clojure更加惰性,但这可能与本问题无关。 - Gordon Gustafson
1
我同意@GordonGustafson的观点。Clojure是严格的。我认为你的意思是它具有内置的惰性类型,例如惰性序列/cons和延迟。要使其成为惰性,它必须是非严格的+具有共享(尽管我仍然投了赞成票)。 - MasterMastic
没有证据表明类型可以增加正确性。 - pankajdoharey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接