35

在为分布式/并发/故障转移/可扩展后端环境考虑 Java 的替代方案时,我发现了 Erlang。我花了一些时间阅读书籍和文章,其中几乎所有人(甚至是 Java 上瘾的人)都说 Erlang 在这种环境中是更好的选择,因为许多有用的东西都是开箱即用的,而且不易出错。

我确信 Erlang 在大多数情况下更快,主要是因为不同的垃圾收集策略(每个进程)、没有共享状态(b/w 线程和进程)以及更紧凑的数据类型。但是当我发现Erlang 与 Java 数学示例的比较时,我感到非常惊讶,其中 Erlang 慢了几个数量级,例如从 x10 到 x100。

即使在并发任务上,也包括多个内核和单个内核。

原因是什么?我想到了这些答案:

  • 在大多数任务中使用 Java 原语 (=> no heap/gc)
  • Java 代码和 Erlang 进程中的线程数相同,因此 Actor 模型在这里没有优势
  • 或者只是 Java 是静态类型的,而 Erlang 不是
  • 还有什么?

如果那是因为这些是非常具体的数学算法,那么任何人都可以展示更多真实/实践性能测试吗?

更新:到目前为止,我得到的答案总结说,Erlang 不是这种特定“快速 Java 案例”的正确工具,但我不清楚的事情 - 这里 Erlang 效率低下的主要原因是什么:动态类型,GC还是糟糕的原生编译?

4

7 回答 7

33

Erlang 不是为数学而构建的。它在构建时考虑到了通信、并行处理和可扩展性,因此针对数学任务对其进行测试有点像测试您的手提钻是否能给您带来耳目一新的按摩体验。

话虽如此,让我们稍微提一下:
如果您想在 JVM 中进行 Erlang 风格的编程,请查看Scala ActorsAkka 框架Vert.x

于 2012-11-29T15:53:37.867 回答
14

除了他们真正测试的内容之外,基准测试永远不适合说任何其他内容。如果您觉得基准测试只是测试原语和经典线程模型,那您就知道了。您现在可以自信地说,Java 在原语数学以及针对这些类型问题的经典线程模型方面比 Erlang 更快。您对大量线程的性能或更多涉及的问题一无所知,因为基准测试没有对此进行测试。

如果您正在做基准测试所测试的数学类型,请使用 Java,因为它显然是适合该工作的工具。如果您想做一些高度可扩展且几乎没有共享状态的事情,请为此找到一个基准,或者至少重新评估 Erlang。

如果你真的需要在 Erlang 中做大量的数学运算,可以考虑使用 HiPE(无论如何考虑一下)。

于 2012-11-29T15:43:56.887 回答
8

正如其他答案所指出的 - Erlang 旨在有效地解决现实生活中的问题,这与基准问题有点相反。

但是我想进一步说明一个方面 - erlang 代码的简洁性(在某些情况下意味着开发的快速性),在比较基准实现之后可以很容易地得出结论。

例如,k-核苷酸基准:
Erlang 版本:http
://benchmarksgame.alioth.debian.org/u64q/program.php?test=k核苷酸&lang=hipe&id=3 Java 版本:http ://benchmarksgame.alioth.debian.org /u64q/program.php?test=k核苷酸&lang=java&id=3

如果您想要更多真实的基准测试,我建议您比较摩托罗拉电信软件的 C++ 和 Erlang

于 2012-11-29T16:20:03.027 回答
7

我对此很感兴趣,因为一些基准非常适合 erlang,例如基因测序。所以在http://benchmarksgame.alioth.debian.org/上,我做的第一件事是查看 C 和 Erlang 的反向补码实现,以及测试细节。我发现测试是有偏差的,因为它没有考虑 erlang 启动 VM /w 调度程序所需的时间,本地编译的 C 启动速度要快得多。这些基准衡量的方式基本上是: time erl -noshell -s revcomp5 main < revcomp-input.txt

现在基准测试显示 Java 用了 1.4 秒,而 erlang /w HiPE 用了 11 秒。运行(单线程)Erlang 代码花了我 0.15 秒,如果不考虑启动 vm 的时间,实际工作负载只用了 3000 微秒( 0.003 秒)。

所以我不知道这是如何进行基准测试的,如果它做了 100 次,那么它是没有意义的,因为启动 erlang VM 的成本将是 x100。如果输入比给出的长很多,那是有道理的,但我在网页上看不到任何细节。为了使托管语言的基准测试更加公平,让代码(Erlang/Java)向 python(正在执行基准测试)发送一个 Unix 信号,表明它达到了启动功能。

现在抛开基准测试不谈,erlang VM 本质上只是在最后执行机器代码,Java VM 也是如此。因此,Erlang 中的数学运算不会比 Java 中花费更长的时间。

Erlang 不擅长的是需要经常改变的数据。例如链式块密码。假设您有字符“0123456789”,现在您的加密将前 2 个字符与 7 相异或,然后通过前两个相加的结果对接下来的两个字符进行异或,然后将前两个字符与当前减去的 2 个字符相异或,然后异或接下来的4个字符..等

因为 Erlang 中的对象是不可变的,这意味着每次改变它时都需要复制整个 char 数组。这就是为什么 erlang 支持称为 NIFS 的东西,它是你可以调用的 C 代码来解决这个确切的问题。事实上,Erlang 附带的所有加密(ssl、aes、blowfish..)和压缩(zlib、..)都是用 C 实现的,从 Erlang 调用 C 的成本也接近 0。

因此,使用 Erlang 可以两全其美,获得 C 的速度和 Erlang 的并行性。

如果我要以最快的方式实现反向补码,我将使用 C 编写变异代码,但使用 Erlang 编写并行代码。假设输入是无限的,我会让 Erlang 在 > <<Line/binary, ">", Rest/binary>> = read_stream Dispatch the block to the first available scheduler via round robin,由无限的 EC2 私有网络隐藏节点组成,每毫秒实时添加到集群中。

然后这些节点通过 NIFS 调用 C 进行处理(C 是 alioth 网站上最快的反向恭维实现),然后将输出发送回节点主控以发送到输入器。

为了在 Erlang 中实现所有这些,我必须像编写单线程程序一样编写代码,创建这段代码需要不到一天的时间。

要在 Java 中实现这一点,我必须编写单线程代码,我必须承担从托管调用到非托管调用的性能损失(因为我们显然将使用 C 实现来完成繁重的工作),然后重写以支持64 核。然后重写它以支持多个CPUS。然后再次重写它以支持集群。然后再次重写以修复内存问题。

简而言之,这就是 Erlang。

于 2016-02-15T21:57:56.693 回答
3

Erlang 解决方案使用 ETS,Erlang Term Storage,它就像一个在单独进程中运行的内存数据库。由于它位于一个单独的进程中,因此必须对进出该进程的所有消息进行序列化/反序列化。我应该认为,这会导致很多缓慢。例如,如果你看一下“regex-dna”基准,Erlang 只比 Java 慢一点,而且它不使用 ETS。

于 2015-03-10T20:25:40.377 回答
2

事实上,erlang 必须为每个值分配内存,而在 java 中,如果你希望它更快,你通常会重用变量,这意味着它对于“紧密循环”基准测试总是更快。

使用 -client 标志和盒装原语对 java 版本进行基准测试并将其与 erlang 进行比较会很有趣。

我认为使用 hipe 是不公平的,因为它不是一个活跃的项目。我很想知道是否有任何关键任务软件在此运行。

于 2012-12-21T22:41:40.333 回答
-8

我对 Erlang 一无所知,但这似乎是一种比较苹果和橘子的方法。您必须知道,十多年来,为了将 Java 性能提高到今天的水平,我们付出了相当大的努力。

(对我来说)志愿者或小公司完成的语言实现无法超越这种努力并不奇怪。

于 2012-11-29T16:13:11.183 回答