55

I came across this old question and did the following experiment with scala 2.10.3.

I rewrote the Scala version to use explicit tail recursion:

import scala.annotation.tailrec

object ScalaMain {
  private val t = 20

  private def run() {
    var i = 10
    while(!isEvenlyDivisible(2, i, t))
      i += 2
    println(i)
  }

  @tailrec private def isEvenlyDivisible(i: Int, a: Int, b: Int): Boolean = {
    if (i > b) true
    else (a % i == 0) && isEvenlyDivisible(i+1, a, b)
  }

  def main(args: Array[String]) {
    val t1 = System.currentTimeMillis()
    var i = 0
    while (i < 20) {
      run()
      i += 1
    }
    val t2 = System.currentTimeMillis()
    println("time: " + (t2 - t1))
  }
}

and compared it to the following Java version. I consciously made the functions non-static for a fair comparison with Scala:

public class JavaMain {
    private final int t = 20;

    private void run() {
        int i = 10;
        while (!isEvenlyDivisible(2, i, t))
            i += 2;
        System.out.println(i);
    }

    private boolean isEvenlyDivisible(int i, int a, int b) {
        if (i > b) return true;
        else return (a % i == 0) && isEvenlyDivisible(i+1, a, b);
    }

    public static void main(String[] args) {
        JavaMain o = new JavaMain();
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < 20; ++i)
          o.run();
        long t2 = System.currentTimeMillis();
        System.out.println("time: " + (t2 - t1));
    }
}

Here are the results on my computer:

> java JavaMain
....
time: 9651
> scala ScalaMain
....
time: 20592

This is scala 2.10.3 on (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).

My question is what is the hidden cost with the scala version?

Many thanks.

4

4 に答える 4

23

私はval

private val t = 20

一定の定義に

private final val t = 20

パフォーマンスが大幅に向上し、現在では両方のバージョンがほぼ同等に機能しているようです [私のシステムでは、更新とコメントを参照してください]。

私はバイトコードを調べていませんが、使用すると、メソッドがあるval t = 20ことがわかりますjavap(そして、そのバージョンはprivate val.

したがって、 a でもメソッドの呼び出しが含まれると思いますが、これは Javaprivate valの a と直接比較することはできません。final

アップデート

私のシステムでは、これらの結果が得られました

Java バージョン: 時刻: 14725

Scala バージョン: 時間: 13228

32 ビット Linux で OpenJDK 1.7 を使用する。

私の経験では、64 ビット システムでの Oracle の JDK は実際にはパフォーマンスが優れているため、これはおそらく、Scala バージョンを支持する他の測定値がさらに優れた結果をもたらすことを説明しています。

Scala バージョンの方がパフォーマンスが優れていることについては、末尾再帰の最適化がここで効果があると思います (Phil の回答を参照してください。Java バージョンが再帰ではなくループを使用するように書き直された場合、再び同じように実行されます)。

于 2014-03-22T18:56:59.960 に答える