Scala perf:为什么这个Scala应用程序比等效的Java应用程序慢30倍?

2022-09-03 04:21:45

我是一个非常熟练的C#开发人员,但需要开始编写在JVM上运行的代码。与C#相比,Java语言的功能很差,所以我对Scala提供的功能很感兴趣。

但是,当听说在Scala中,所有运算符都只是方法时,我开始怀疑这会对数学密集型计算的性能影响(这对于我的团队编写的应用程序类型很重要)。

所以我运行了一些简单的基于int的测试,发现Scala比等效的Java代码慢30倍。不好!谁能告诉我我做错了什么?或者如何提高scala示例的计算性能以与Java相提并论?

UPDATE1:正如前两个答案所指出的,我是一个超级菜鸟,并在IntelliJ IDE中运行它。我不知道如何通过java命令行运行scala应用程序,这可能是IntelliJ问题。感谢大家的帮助,在我继续perf测试之前,我需要研究scala的简单命令行执行,因为IDE给出的结果显然太不准确了。

UPDATE2:路易吉在评论中说在IntelliJ中他得到了相等的时间,所以似乎我的疯狂差异不是由于IntelliJ?关于这可能是什么的任何其他想法?我将尝试通过命令行运行此内容,并使用我的结果发布更新。

UPDATE3:通过命令行运行此命令后,我得到了相同的30x性能差异。
我的电脑是3核AMD x64 3.4Ghz,运行J2SE 6 jdk 64bit 1.6.0_31,Window7。

以下是我的运行时:Java:210ms。
Scala:在2000和7400ms之间(通常是7000范围)

所以,我想这个问题仍然悬而未决。为什么 scala 在我的平台上运行得这么慢?java 64bit运行时或Java 6?

运行时版本:

C:\Users\jason>java -showversion
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)

C:\Users\jason>scala
Welcome to Scala version 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).

UPDATE 4 虽然我的原始测试有30倍的差异,但将迭代次数增加到100000000会导致差异缩小到大约33%,所以看起来scala仍然被我的机器上一些未知的初始化成本所主导。我将以评分最高的答案结束本文,因为我认为我们不会发现性能问题,因为除了我看到问题之外,没有人:(

*更新5,解决方案:基于我得到的2个答案的帮助,我找出了问题,请参阅下面的答案以获取更多详细信息(摘要:第一次调用System.nanoTime()需要很长时间)*

以下是我的示例应用:

//scala
object HelloWorld {
  //extends Application {
  def main(args: Array[String]) {
    println("hello scala")
    var total: Long = 0
    var i: Long = 0
    var x: Long=0;
    //warm up of the JVM to avoid timing of runtime initialization
    while (i < 100000)
    {
      x=i;
      x += x - 1;
      x -= x + 1;
      x += 1;
      x -= 1;
      total += x;
      i+=1;
    }
    //reset variables
    total = 0
    i = 0;
    //start timing
    var start: Long = System.nanoTime

    //run test
    while (i < 100000) {
      x=i;
      x += x - 1;
      x -= x + 1;
      x += 1;
      x -= 1;

      total += x;
      i+=1;
    }
    var end: Long = System.nanoTime
    System.out.println("ms, checksum = ")
    System.out.println((end - start) / 1000)
    System.out.println(total)
  }
}

这是Java的等价物,快30倍

//java
public class app {
    public static void main(String[] args)
    {
        String message = "hello, java";
        System.out.println(message);
        long total = 0;
        //warm up of the JVM to avoid timing of runtime initialization
        for(long i=0;i< 100000;i++)
        {
            long x=i;
            x+=x-1;
            x-=x+1;
            x++;
            x--;
            total+=x;
        }
        //reset variables
        total = 0;
        //start timing and run test
        long start = System.nanoTime();
        for(long i=0;i< 100000;i++)
        {
            long x=i;
            x+=x-1;
            x-=x+1;
            x++;
            x--;
            total+=x;
        }
        long end = System.nanoTime();
        System.out.println("ms, checksum = ");
        System.out.println((end-start)/1000);
        System.out.println(total);
    }
}

答案 1

所以,我想我自己想出了答案。

问题出在对 的调用中。这样做会产生一些初始化成本(加载Java基础库等),从Java运行时调用时加载的成本比从Scala运行时调用的成本要低得多。System.nanoTime

我通过更改总计的初始值来证明这一点,而不是将其设置为

var total: Long = System.nanoTime()

这是在第一个“预热”循环之前添加的,现在这样做会使应用程序的两个版本(Java和Scala)同时运行:大约2100个1000000次迭代。

感谢你们在这方面的帮助,如果没有你们的帮助,我就不会弄清楚这一点。

ps:我会把“接受的答案”原封不动地留下来,因为如果没有他的帮助,我将无法追踪到这一点。


答案 2

我已经重新运行了你的代码(并增加了周期数x1000,以便为基准测试提供一些意义)。

结果:

Scala: 92 ms
Java: 59 ms

你可以看到Java的速度提高了30%。

看看字节码,我可以说两个版本几乎相同 - 所以差异真的很奇怪(字节码列表很长,所以我不会在这里发布)。

增加计数 x10000 会得到以下结果:

Scala: 884 ms
Java: 588 ms

由于结果相当稳定,因此应该潜伏在某个地方的一些恒定因素。也许在某些参数中,“scala”运行器传递给JVM?

编辑:

我的配置:

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

$ scala -version
Scala code runner version 2.9.0.1 -- Copyright 2002-2011, LAMP/EPFL

$ inxi -SCD
System:    Host the-big-maker Kernel 2.6.35-22-generic x86_64 (64 bit) Distro Linux Mint 10 Julia
CPU:       Quad core AMD Phenom II X4 965 (-MCP-) cache 2048 KB flags (lm nx sse sse2 sse3 sse4a svm) 
           Clock Speeds: (1) 800.00 MHz (2) 800.00 MHz (3) 800.00 MHz (4) 800.00 MHz
Disks:     HDD Total Size: 750.2GB (5.8% used) 1: /dev/sda OCZ 90.0GB 
           2: /dev/sdb ST3500413AS 500.1GB 3: /dev/sdc ST3802110A 80.0GB 
           4: /dev/sdd Maxtor_6Y080M0 80.0GB 

推荐