Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么用于斐波那契计算的简单Scala tailrec循环比Java循环快3倍?_Java_Scala_Tail Recursion_Jmh - Fatal编程技术网

为什么用于斐波那契计算的简单Scala tailrec循环比Java循环快3倍?

为什么用于斐波那契计算的简单Scala tailrec循环比Java循环快3倍?,java,scala,tail-recursion,jmh,Java,Scala,Tail Recursion,Jmh,Scala 代码: 字节码: private long fastLoop(int, long, long); Code: 0: iload_1 1: iconst_1 2: if_icmple 21 5: iload_1 6: iconst_1 7: isub 8: lload 4 10: lload_2 11: lload

Scala

代码:

字节码:

  private long fastLoop(int, long, long);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmple     21
       5: iload_1
       6: iconst_1
       7: isub
       8: lload         4
      10: lload_2
      11: lload         4
      13: ladd
      14: lstore        4
      16: lstore_2
      17: istore_1
      18: goto          0
      21: lload         4
      23: lreturn
  private long fastLoop(int, long, long);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmple     24
       5: lload_2
       6: lload         4
       8: ladd
       9: lstore        6
      11: lload         4
      13: lstore_2
      14: lload         6
      16: lstore        4
      18: iinc          1, -1
      21: goto          0
      24: lload         4
      26: lreturn
结果是
53879289.462±6289454.961操作/s

Java

代码:

字节码:

  private long fastLoop(int, long, long);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmple     21
       5: iload_1
       6: iconst_1
       7: isub
       8: lload         4
      10: lload_2
      11: lload         4
      13: ladd
      14: lstore        4
      16: lstore_2
      17: istore_1
      18: goto          0
      21: lload         4
      23: lreturn
  private long fastLoop(int, long, long);
    Code:
       0: iload_1
       1: iconst_1
       2: if_icmple     24
       5: lload_2
       6: lload         4
       8: ladd
       9: lstore        6
      11: lload         4
      13: lstore_2
      14: lload         6
      16: lstore        4
      18: iinc          1, -1
      21: goto          0
      24: lload         4
      26: lreturn
结果是
17444340.812±9508030.117次/s

是的,这取决于环境参数(JDK版本、CPU型号和RAM频率)和动态状态。但是,为什么在相同的环境中,几乎相同的字节码可以为函数参数的范围产生稳定的2x-3x差异

以下是我的笔记本电脑中不同函数参数值的ops/s编号列表,该笔记本电脑采用Intel(R)Core(TM)i7-2640M CPU@2.80GHz(最大3.50GHz)、RAM 12Gb DDR3-1333、Ubuntu 14.10、Oracle JDK 1.8.0_40-b25 64位:

[info] Benchmark            (n)   Mode  Cnt          Score          Error  Units
[info] JavaFibonacci.loop     2  thrpt    5  171776163.027 ±  4620419.353  ops/s
[info] JavaFibonacci.loop     4  thrpt    5  144793748.362 ± 25506649.671  ops/s
[info] JavaFibonacci.loop     8  thrpt    5   67271848.598 ± 15133193.309  ops/s
[info] JavaFibonacci.loop    16  thrpt    5   54552795.336 ± 17398924.190  ops/s
[info] JavaFibonacci.loop    32  thrpt    5   41156886.101 ± 12905023.289  ops/s
[info] JavaFibonacci.loop    64  thrpt    5   24407771.671 ±  4614357.030  ops/s
[info] ScalaFibonacci.loop    2  thrpt    5  148926292.076 ± 23673126.125  ops/s
[info] ScalaFibonacci.loop    4  thrpt    5  139184195.527 ± 30616384.925  ops/s
[info] ScalaFibonacci.loop    8  thrpt    5  109050091.514 ± 23506756.224  ops/s
[info] ScalaFibonacci.loop   16  thrpt    5   81290743.288 ±  5214733.740  ops/s
[info] ScalaFibonacci.loop   32  thrpt    5   38937420.431 ±  8324732.107  ops/s
[info] ScalaFibonacci.loop   64  thrpt    5   22641295.988 ±  5961435.507  ops/s

另外一个问题是“为什么ops/s的值会以上述非线性方式下降?”

是的,我错了,错过了测试方法不仅仅是
快速循环调用:

Scala

  @Benchmark
  def loop(): BigInt =
    if (n > 92) loop(n - 91, 4660046610375530309L, 7540113804746346429L)
    else fastLoop(n)
 @Benchmark
    public BigInteger loop() {
        return n > 92 ?
                loop(n - 91, BigInteger.valueOf(4660046610375530309L), BigInteger.valueOf(7540113804746346429L)) :
                BigInteger.valueOf(fastLoop(n, 0, 1));
    }
Java

  @Benchmark
  def loop(): BigInt =
    if (n > 92) loop(n - 91, 4660046610375530309L, 7540113804746346429L)
    else fastLoop(n)
 @Benchmark
    public BigInteger loop() {
        return n > 92 ?
                loop(n - 91, BigInteger.valueOf(4660046610375530309L), BigInteger.valueOf(7540113804746346429L)) :
                BigInteger.valueOf(fastLoop(n, 0, 1));
    }
正如Aleksey所指出的,很多时间都花在从
Long/Long
BigInt/biginger
的转换上

我编写了单独的基准测试,只测试
fastLoop(n,0,1)
call。以下是它们的结果:

[info] JavaFibonacci.fastLoop     2  thrpt    5  338071686.910 ± 66146042.535  ops/s
[info] JavaFibonacci.fastLoop     4  thrpt    5  231066635.073 ±  3702419.585  ops/s
[info] JavaFibonacci.fastLoop     8  thrpt    5  174832245.690 ± 36491363.939  ops/s
[info] JavaFibonacci.fastLoop    16  thrpt    5   95162799.968 ± 16151609.596  ops/s
[info] JavaFibonacci.fastLoop    32  thrpt    5   60197918.766 ± 10662747.434  ops/s
[info] JavaFibonacci.fastLoop    64  thrpt    5   29564087.602 ±  3610164.011  ops/s
[info] ScalaFibonacci.fastLoop    2  thrpt    5  336588218.560 ± 56762496.725  ops/s
[info] ScalaFibonacci.fastLoop    4  thrpt    5  224918874.670 ± 35499107.133  ops/s
[info] ScalaFibonacci.fastLoop    8  thrpt    5  121952667.394 ± 17314931.711  ops/s
[info] ScalaFibonacci.fastLoop   16  thrpt    5   96573968.960 ± 12757890.175  ops/s
[info] ScalaFibonacci.fastLoop   32  thrpt    5   59462408.940 ± 14924369.138  ops/s
[info] ScalaFibonacci.fastLoop   64  thrpt    5   28922994.377 ±  7209467.197  ops/s
我学到的教训:

  • Scala隐含着它可以吃掉很多性能,但容易被忽略

  • 与Java的BigInteger相比,在Scala中兑现BigInt值可以加快某些函数的速度


您必须首先检查字节码。这是一个非常相似的问题,不同之处在于隐式循环展开。你能详细介绍一下你使用的bechmarking机制吗?看起来你的测量技术有问题的可能性要比实际速度慢的可能性大得多。你读过这篇文章吗?JVM的字节码不会影响性能,您必须重复本文中的所有研究。请提供stack和perf Profiler输出。还请注意错误相当大。如果您使用“适当”的单位,比如“ops/us”,那么就可以清楚地看到上表中Java/Scala结果的大多数差异都不显著。您还必须跟踪调用
快速循环前后发生的情况。我为您的GitHub项目挖掘了数据,在我的机器上,n=10时,只有20%的CPU时间用于
fastLoop
,其余80%用于处理
BigInt
/
biginger
。请使用“适当”单位,例如“ops/us”。太难读了谢谢你,伊万!我已切换到ops/ms(因为ops/us报告过于粗糙,如~10^-4)