为什么Java在这种情况下比C更快(和更慢)?

tcn*_*tcn 3 java performance gcc jvm jvm-hotspot

一些人刚刚开始通过阅读K&R来学习C,并在第一页上打印出了华氏到细胞的转换循环:

#include <stdio.h>

main ()                                                                                                                                                       
{
  int fahr;                                                                                                                                                    

  for (fahr = 0; fahr<= 200000000; fahr = fahr + 20)                                                                                                                                                                                
    printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                                                                                                       
}   
Run Code Online (Sandbox Code Playgroud)

他被告知Java很慢.所以,告诉他Java现在非常具有竞争力,但C在这个简单的情况下可能会更快.想要证明他并且基本上添加了"System.out".在printf()前面.

它慢了10倍.方式太多了.我很困惑.想到String对象创建,GC,-server,yada,yada,yada.

当我发现几乎100%的时间实际上用在printf()(PrintSteam.write()输出管道到/ dev/null)时,我感到更加困惑.

在一些摆弄之后我想出了这个(现在不做%f的四舍五入):

public static void main(String... args) throws Exception {                                                                                                       
   int fahr=0;                                                                                                                                                    

    PrintWriter out = new PrintWriter(Channels.newWriter(Channels.newChannel(System.out), "US-ASCII") );                                                                                                

    int max = 2000000000;                                                                                                                                         
    for (fahr = 0; fahr<= max; fahr = fahr + 20)
      // out.printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                       
      out.println( fahr + "\t" + f(((5.0 / 9.0) * (fahr-32)) ));                                                                                                        

    out.close();                                                                                                                                            
 }                                                                                                                                                                

 private static final String f(double d) {                                                                                                                         
      return (int)d + "." + (int)((d - (int)d)*100);                                                                                                              
 }                                                                                                                                                           
} 
Run Code Online (Sandbox Code Playgroud)

所以,这使用NIO.并且它在两台测试的机器上胜过 gcc -O2.

问题:

  • 为什么从C到Java(即PrintStream)的文字转录如此之慢?
  • (为什么评论out.printf()这么慢[可能性能会随着时间的推移而降低]?)
  • 最后:为什么我的解决方案比C更快(包括JVM启动时间)?

peu*_*feu 5

为什么从C到Java(即PrintStream)的文字转录如此之慢?

您正在对System.out和各种stdio(C与Java)实现进行基准测试

(为什么注释out.printf()这么慢[可能性能会随着时间的推移而降低]?)

将浮点数转换为字符串(反之亦然)是一个非常复杂和缓慢的操作.看看glibc的源代码.

最后:为什么我的解决方案比C更快(包括JVM启动时间)?

因为您是基准测试和比较不同的东西:

  • 一个java代码,它将整数转换为字符串(由于显而易见的原因,它比浮点快得多)和一些简单的字符串操作,希望java VM可以做得很好,加上out.println()
  • 每个循环迭代运行解释语言的C代码(是的,printf是一个小语言的解释器,"%d\t%6.2f \n"是一个程序)并执行浮点到字符串转换(它本身比整数慢很多倍,加上stdio.

目前还不清楚C版本是使用单精度还是双精度.