54

如果你已经接受了函数式编程范式,那么你很可能同时喜欢 Erlang 和 Haskell。两者都具有纯功能内核和其他优点,例如轻量级线程,使其非常适合多核世界。但也有一些不同之处。

Erlang 是一种经过商业验证的容错语言,具有成熟的分布模型。它具有一个看似独特的功能,即通过热代码加载在运行时升级其版本的能力。(太酷了!)

另一方面,Haskell 拥有所有主流语言中最复杂的类型系统。(我将“主流”定义为任何有出版 O'Reilly 书籍的语言,因此 Haskell 很重要。)它的直线单线程性能看起来优于 Erlang 的,它的轻量级线程看起来也更轻。

我正在尝试为我余下的编码生涯构建一个开发平台,并且想知道是否可以混合 Erlang 和 Haskell 来实现最佳的平台。这个问题有两个部分:

  1. 我想使用 Erlang 作为一种容错 MPI 来将 GHC 运行时实例粘合在一起。每个 GHC 运行时将有一个 Erlang 进程。如果“不可能的事情发生了”并且 GHC 运行时死了,那么 Erlang 进程会以某种方式检测到这一点并且也会死掉。Erlang 的热代码加载和分发功能将继续工作。GHC 运行时可以配置为仅使用一个内核,或本地计算机上的所有内核,或两者之间的任何组合。一旦编写了 Erlang 库,其余的 Erlang 级别代码应该是纯粹的样板文件,并在每个应用程序的基础上自动生成。(例如,可能通过 Haskell DSL。)如何实现至少其中的一些?
  2. 我希望 Erlang 和 Haskell 能够共享同一个垃圾收集器。(这比 1 更进一步。)在 JVM 和 CLR 上运行的语言通过共享运行时实现了更大的质量。我了解在 JVM 或 CLR 上运行 Erlang(热代码加载)和 Haskell(更高种类的多态性)存在技术限制。但是如果只拆分垃圾收集器呢?(有点像函数式语言运行时的开始。)分配显然仍然必须非常快,所以可能需要静态链接该位。并且应该有一些机制来区分可变堆和不可变堆(包括惰性写入一次内存),因为 GHC 需要这个。修改 HIPE 和 GHC 以便垃圾收集器可以共享一个堆是否可行?

请回答任何经验(正面或负面)、想法或建议。事实上,任何反馈(没有直接滥用!)都是受欢迎的。

更新

感谢迄今为止所有 4 条回复——每条回复都至少教会了我一件我不知道的有用的事情。

关于编码生活的其余部分-我将其包括在面颊上以引发辩论,但实际上是真的。我有一个项目,我打算一直工作到我死,它需要一个稳定的平台。

在我上面提出的平台中,我只会写 Haskell,因为样板 Erlang 会自动生成。那么 Haskell 会持续多久呢?好吧,Lisp 仍然在我们身边,而且看起来它不会很快消失。Haskell 是 BSD3 开源并已达到临界质量。如果编程本身在 50 年后仍然存在,我希望 Haskell 或 Haskell 的一些持续发展仍然存在。

更新 2 以响应 rvirding 的帖子

同意——实现一个完整的“Erskell/Haslang”通用虚拟机可能不是绝对不可能的,但确实非常困难。仅将垃圾收集器级别共享为类似于 VM 的东西,虽然仍然很困难,但对我来说听起来要困难一个数量级。在垃圾收集模型中,函数式语言必须有很多共同点——不可变数据(包括 thunk)的不普遍性以及对快速分配的要求。因此,将通用性与单体 VM 紧密捆绑在一起的事实似乎有点奇怪。

虚拟机确实有助于实现临界质量。看看像 F# 和 Scala 这样的“精简”函数式语言是如何起飞的。Scala 可能没有 Erlang 的绝对容错能力,但它为许多与 JVM 相关联的人提供了一条逃生路线。

虽然拥有单个堆使得消息传递速度非常快,但它引入了许多其他问题,主要是进行 GC 变得更加困难,因为它必须是交互式且全局非中断的,因此您不能使用与 per- 相同的更简单算法进程堆模型。

绝对,这对我来说很有意义。GHC 开发团队中非常聪明的人似乎正试图通过并行的“stop the world”GC 解决部分问题。

http://research.microsoft.com/en-us/um/people/simonpj/papers/parallel-gc/par-gc-ismm08.pdf

(显然“停止世界”对于一般 Erlang 的主要用例来说是行不通的。)但即使在“停止世界”可以使用的用例中,它们的加速似乎也不是普遍的。所以我同意你的看法,不太可能有一个普遍最好的 GC,这就是我在我的问题的第 1 部分中指定的原因

GHC 运行时可以配置为仅使用一个内核,或本地计算机上的所有内核,或两者之间的任何组合。

这样,对于给定的用例,我可以在基准测试之后选择采用 Erlang 方式,并运行一个 GHC 运行时(使用单线程 GC)加上每个内核一个 Erlang 进程,并让 Erlang 在内核之间复制内存以获得良好的局部性.

或者,在双处理器机器上,每个处理器有 4 个内核,处理器上有良好的内存带宽,基准测试可能建议我运行一个 GHC 运行时(使用并行 GC)加上每个处理器一个 Erlang 进程。

在这两种情况下,如果 Erlang 和 GHC 可以共享一个堆,那么共享可能会以某种方式绑定到在单个内核上运行的单个 OS 线程。(我在这里超出了我的深度,这就是我问这个问题的原因。)

我还有另一个议程——独立于 GC 对功能语言进行基准测试。我经常阅读 OCaml v GHC v Erlang v 的基准测试结果......并且想知道不同的 GC 混淆了多少结果。如果 GC 的选择可以与函数式语言的选择正交怎么办?GC到底有多贵?看到这个魔鬼倡导者博客文章

http://john.freml.in/garbage-collection-harmful

由我的 Lisp 朋友 John Fremlin 撰写,他很迷人地给出了他的帖子标题“自动垃圾收集是垃圾”。当约翰声称 GC 很慢并且没有真正加速时,我希望能够用一些数字来反驳。

4

6 回答 6

33

许多 Haskell 和 Erlang 人对 Erlang 监督分布的模型感兴趣,而 Haskell 并行运行共享内存节点来执行所有数字运算/逻辑。

一个开始是 haskell-erlang 库:http ://hackage.haskell.org/package/erlang

我们在 Ruby 领域也有类似的努力,通过 Hubris:http: //github.com/mwotton/Hubris/tree/master

现在的问题是找人真正推动 Erlang / Haskell 互操作以找出棘手的问题。

于 2009-09-09T10:45:45.793 回答
5

您将在 Haskell 和 Erlang 之间混合使用 GC,度过一段有趣的时光。Erlang 使用每个进程的堆并在进程之间复制数据——因为 Haskell 甚至没有进程的概念,我不确定你将如何在两者之间映射这个“通用”GC。此外,为了获得最佳性能,Erlang 使用了各种分配器,每个分配器都有一些稍微调整的行为,我确信这会影响 GC 子系统。

与软件中的所有事物一样,抽象是有代价的。在这种情况下,我宁愿怀疑您必须引入如此多的层才能使两种语言克服它们的阻抗不匹配问题,以至于您最终会得到一个性能不高(或有用)的通用 VM。

底线——拥抱差异!不在同一进程中运行所有内容有巨大的优势,特别是从可靠性的角度来看。另外,我认为期望一种语言/虚拟机能在你的余生中持续存在有点天真(除非你计划 a.)短时间生活或 b.)成为某种只适用于 a 的代码修士单个项目)。软件开发完全取决于思维敏捷性,并愿意使用最好的可用工具来构建快速、可靠的代码。

于 2009-09-09T12:39:53.480 回答
5

虽然这是一个相当老的线程,但如果读者仍然感兴趣,那么值得一看Cloud Haskell,它为 GHC 稳定版带来了 Erlang 风格的并发和分发。

即将推出的分布式进程平台库增加了对 OTP 式结构的支持,例如 gen_servers、监督树和各种其他从 Erlang/OTP 借用和启发的“haskell 风格”抽象。

于 2013-01-23T14:59:34.577 回答
4
  1. 您可以使用 OTP gen_supervisor 进程来监控您使用 open_port() 生成的 Haskell 实例。根据“端口”的退出方式,您将能够重新启动它或决定它故意停止并让相应的 Erlang 进程也死掉。

  2. 富格达布迪。即使是您所说的这些与语言无关的虚拟机,有时也会在语言之间传递数据时遇到问题。您应该以某种方式在两者之间序列化数据:数据库、XML-RPC 之类的。

顺便说一句,为您的余生提供单一平台的想法也可能是不切实际的。计算技术和时尚变化太频繁,以至于无法期望您可以永远只使用一种语言。您的问题指出了这一点:即使在今天,也没有一种语言可以满足我们的所有愿望。

于 2009-09-09T05:20:13.517 回答
4

正如 dizzyd 在他的评论中提到的,并非消息中的所有数据都被复制,大型二进制文件存在于进程堆之外并且不会被复制。

使用不同的内存结构来避免拥有单独的每个进程堆当然是可能的,并且在许多早期的实现中已经完成。虽然拥有单个堆使得消息传递速度非常快,但它引入了许多其他问题,主要是因为 GC 必须是交互式且全局非中断的,所以执行 GC 变得更加困难,因此您不能使用与 per- 相同的更简单算法进程堆模型。

只要我们使用不可变的数据结构,鲁棒性和安全性就没有问题。决定使用哪种内存和 GC 模型是一个很大的权衡,不幸的是普遍存在最好的模型。

虽然 Haskell 和 Erlang 都是函数式语言,但它们在许多方面是非常不同的语言,并且具有非常不同的实现。很难想出可以有效处理两种语言的“Erskell”(或 Haslang)机器。我个人认为将它们分开并确保它们之间有一个非常好的接口会更好。

于 2009-09-09T15:34:55.023 回答
2

CLR 支持使用显式tail操作码(如 F# 所使用的)进行尾调用优化,而 JVM(还)没有等效的操作码,这限制了这种语言风格的实现。使用单独AppDomain的 s 确实允许 CLR 热交换代码(参见例如这篇博客文章,展示了它是如何完成的)。

西蒙·佩顿·琼斯 (Simon Peyton Jones) 与唐赛姆 (Don Syme) 和微软研究院的 F# 团队一起工作,如果我们最终没有看到具有某种官方地位的 IronHaskell,那将是非常令人失望的。IronErlang 将是一个有趣的项目——最大的工作可能是移植绿色线程调度程序,而不需要像 Windows 工作流引擎那样重量级,或者必须在 CLR 上运行 BEAM VM。

于 2009-09-09T06:57:19.927 回答