在所有这些小数学基准测试中,为什么Erlang比Java慢?

yet*_*der 34 java erlang performance compare

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

我确信Erlang在大多数情况下更快,主要是因为不同的垃圾收集策略(每个进程),缺少共享状态(黑白线程和进程)和更紧凑的数据类型.但是当我发现Erlang与Java数学样本的比较时,我感到非常惊讶,其中Erlang的速度慢了几个,例如从x10到x100.

即使是并发任务,也可以在几个核心和一个核心上完成.

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

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

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

更新:到目前为止,我已经得到了答案,总结了Erlang不是这种特定"快速Java案例"的正确工具,但我不清楚这一点 - 这里Erlang效率低下的主要原因是什么:动态类型,GC还是可怜的原生编译?

npe*_*npe 31

Erlang不是为数学而建的.它的构建考虑了通信,并行处理和可扩展性,因此对数学任务进行测试有点像测试你的手提钻是否能给你带来清爽的按摩体验.

这就是说,我们offtop一点:
如果你想在JVM二郎风格的节目,看看Scala的演员阿卡框架Vert.x.

  • 我不知道Erlang足以说明原因.当然JVM有它的问题.我的意思是:_"使用适合您问题的工具"_.Erlang非常适合发送消息.处理它们不一定非常好.如果进行数学计算,请使用Matlab,C或汇编程序.如果进行统计,请使用R等,依此类推. (4认同)

Emi*_*röm 14

除了他们真正测试的东西之外,基准测试对于说其他任何东西都不好.如果您认为基准测试只是测试基元和经典线程模型,那么您就可以获得相关知识.你现在可以有信心地说,Java在基元数学方面比Erlang更快,而且对于那些类型的问题也是经典的线程模型.您对大量线程的性能或更多涉及的问题一无所知,因为基准测试没有对此进行测试.

如果您正在使用基准测试的数学类型,请使用Java,因为它显然是该工作的正确工具.如果你想做一些可扩展的东西,几乎没有共享状态,找到一个基准或者至少重新评估Erlang.

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

  • 顺便说一句,我明白为什么java在这里更快 - 几乎所有的都是编译为native + no heap,+ static.那么erlang怎么样:因为它的HiPE不是编译成本机的吗?堆怎么样?或者只有静态与动态在这里扮演重要角色? (4认同)
  • 这些基准测试均采用HiPE erlang btw (2认同)

ste*_*emm 8

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

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

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

如果你想要更多真实的基准测试,我建议你比较C++和Erlang For Motorola Telecoms Software


Van*_*s S 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",现在您的加密xors前两个字符乘以7,然后xors接下来的两个字符由前两个字符的结果添加,然后xors前两个字符减去当前2的结果,然后xors接下来的4个字符..等等

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

因此,使用Erlang可以获得两全其美的效果,您可以通过Erlang的并行性获得C的速度.

如果我以尽可能快的方式实现反向补码,我会使用C编写变异代码,但使用Erlang编写并行代码.假设无限输入,我会让Erlang拆分> <<Line/binary, ">", Rest/binary>> = read_stream 通过循环将块发送到第一个可用的调度程序,循环由无限的EC2专用网络隐藏节点组成,每毫秒实时添加到集群.

那些节点然后通过NIFS调用C进行处理(C是对于alioth网站反向补充的最快实现),然后将输出发送回节点主机以发送到计算机.

要在Erlang中实现所有这些,我必须编写代码,就像我编写单线程程序一样,创建此代码需要一天时间.

要在Java中实现这一点,我将不得不编写单线程代码,我将不得不考虑从Managed到Unmanaged调用的性能(因为我们将使用C实现显然是为了grunt工作),然后重写为支持64核心.然后重写它以支持多个CPUS.然后再次重写它以支持群集.然后再次重写它以修复内存问题.

简而言之就是Erlang.