Java比C更快

8
今天我进行了一个简单的测试,比较了Java和C之间的速度 - 一个简单的循环让整数"i"从0增加到20亿。
我真的期望C语言比Java更快。但结果却让我感到惊讶:
Java所需的时间(以秒为单位):约1.8
C所需的时间(以秒为单位):约3.6
我不认为Java是一种更快的语言,但我也不明白为什么在我的简单程序中,Java中的循环速度是C的两倍?
我在程序中犯了一个重要错误吗?或者MinGW的编译器配置有问题吗?
public class Jrand {

 public static void main (String[] args) {

    long startTime = System.currentTimeMillis();
    int i; 
    for (i = 0; i < 2000000000; i++) {
        // Do nothing!
    }
    long endTime = System.currentTimeMillis();
    float totalTime = (endTime - startTime);

    System.out.println("time: " + totalTime/1000);
 }

}

C程序

#include<stdio.h>
#include<stdlib.h>
#include <time.h>
int main () {

    clock_t startTime;
    startTime = clock();

    int i;
    for (i = 0; i <= 2000000000; i++) {
        // Do nothing
    }
    clock_t endTime;
    endTime = clock();

    float totalTime = endTime - startTime;
    printf("%f", totalTime/1000);

    return 0;
}

3
在Java中,循环很可能会被忽略。尝试在循环中执行有意义的操作,比如更新一个总和并在循环结束后打印它。另请参阅此线程 - Sanjay T. Sharma
4
优化器。正如Sanjay所说。 - Devolus
11
你是否为 C 代码开启了优化?我猜你可能没有,否则你的 C 代码应该会立即返回 0 秒。 - Mysticial
1
我想加入一些哲学的注解:简单的速度比较通常是不可靠的,因为它们没有补偿影响速度的多种不同因素。 - PM 77-1
5
通常情况下,语言A比语言B更快这种情况基本上是不存在的。但是,用语言A编写的程序X可能比用语言B编写的程序Y更快。 - Louis Wasserman
8
“我认为 Java 并不是一种更快的编程语言。” 固守教条,无视证据。很棒(!) - Richard Tingle
3个回答

24

重新使用除了-O0(例如-O2)之外的任何优化级别重新构建您的C版本,您会发现它运行时间为0秒。因此,Java版本需要1.6秒才能完成无操作,而C版本只需要0.0秒(实际上大约为0.00005秒)就能完成相同无操作。


11
也许是在他的系统上。在我旧笔记本电脑(Core 2 Duo)第一次运行时,Java版本需要0.059秒...这只是JVM启动时间,可能是磁盘IO引起的。以防这里有任何Java批评者。 - Maarten Bodewes
谢谢!我使用了 -O2 并在循环内添加了一个简单的计算。C 语言:0.0000 秒。Java:6.7 秒。后者也可以进行优化吗? - Björn Hallström
@owlstead:0.059秒的启动开销足以抨击Java。它比典型帧速率/刷新率的帧时间还要长。 - R.. GitHub STOP HELPING ICE
这是虚拟机的启动时间,在运行了3次之后,它降至0.01。它需要启动一些线程来进行后台垃圾回收等操作。也许这使得它对于需要短时间运行的命令行应用程序不太有用,但仅此而已。 - Maarten Bodewes
对于每次网络连接运行一次的程序(通过inetd、传统的cgi等方式),这也是相当棘手的问题。 - R.. GitHub STOP HELPING ICE
我的问题是,为什么Java需要6.7秒才能什么都不做?它在做什么? - alexyorke

10

Java在消除无用代码方面更为积极。它不太可能假设开发人员知道他们在做什么。你计时的不是循环本身,而是Java检测和消除循环所需的时间。

简而言之,Java通常更快地执行无用操作。

此外,您可能会发现,如果优化C代码并删除调试信息,它将执行相同的操作,而且很可能更短。


7
任何像样的C编译器都不会为无用循环生成任何代码,除非您有意地禁用了优化,这是一种单步执行程序并能够理解抽象机器流程的工具。 - R.. GitHub STOP HELPING ICE

1
如果你想进行基准测试,而不是什么都不做,可以尝试在每次迭代中计算一些有用的东西。例如,在某个其他变量中计数循环,并确保在最后使用它(例如通过打印),这样它就不会被优化掉。
另外一些简单的测试可能包括线性访问数组(仅读取)、将元素从一个数组复制到另一个数组(读写)或对数据执行一些操作。其中一些情况可能很有趣,因为它们展示了几个非常简单的编译器优化,您稍后可以在结果二进制/字节码中看到,例如循环展开、寄存器分配,甚至更复杂的向量化或代码移动等。另一方面,Java可能会采用一些更糟糕的技巧,如即时编译(动态重新编译)。
编译器优化的范围非常广泛,您刚刚遇到了最基本的——消除无用代码 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接