为什么 JavaScript 似乎比 C 快 4 倍?

新手上路,请多包涵

很长一段时间以来,我一直认为 C++ 比 JavaScript 更快。但是,今天我做了一个基准脚本来比较两种语言的浮点计算速度,结果令人惊叹!

JavaScript 似乎比 C++ 快 4 倍!

我让这两种语言在我的 i5-430M 笔记本电脑上做同样的工作,执行 a = a + b 100000000 次。 C++ 大约需要 410 毫秒,而 JavaScript 只需要大约 120 毫秒。

我真的不知道为什么 JavaScript 在这种情况下运行得如此之快。谁能解释一下?

我用于 JavaScript 的代码是(使用 Node.js 运行):

 (function() {
    var a = 3.1415926, b = 2.718;
    var i, j, d1, d2;
    for(j=0; j<10; j++) {
        d1 = new Date();
        for(i=0; i<100000000; i++) {
            a = a + b;
        }
        d2 = new Date();
        console.log("Time Cost:" + (d2.getTime() - d1.getTime()) + "ms");
    }
    console.log("a = " + a);
})();

C++(由g++编译)的代码是:

 #include <stdio.h>
#include <ctime>

int main() {
    double a = 3.1415926, b = 2.718;
    int i, j;
    clock_t start, end;
    for(j=0; j<10; j++) {
        start = clock();
        for(i=0; i<100000000; i++) {
            a = a + b;
        }
        end = clock();
        printf("Time Cost: %dms\n", (end - start) * 1000 / CLOCKS_PER_SEC);
    }
    printf("a = %lf\n", a);
    return 0;
}

原文由 streaver91 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

如果您使用的是 Linux 系统(至少在这种情况下符合 POSIX),我可能会给您一些坏消息。 clock() 调用返回程序消耗的时钟滴答数,并由 CLOCKS_PER_SEC 缩放,即 1,000,000

这意味着,如果您 这样的系统上,那么您在 C 语言中以 微秒 为单位,在 JavaScript 中以 毫秒 为单位(根据 JS 在线文档)。因此,相比 JS 快四倍,C++ 实际上快了 250 倍。

现在可能是您在一个系统上,其中 CLOCKS_PER_SECOND 不是一百万,您可以在系统上运行以下程序以查看它是否按相同的值缩放:

 #include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define MILLION * 1000000

static void commaOut (int n, char c) {
    if (n < 1000) {
        printf ("%d%c", n, c);
        return;
    }

    commaOut (n / 1000, ',');
    printf ("%03d%c", n % 1000, c);
}

int main (int argc, char *argv[]) {
    int i;

    system("date");
    clock_t start = clock();
    clock_t end = start;

    while (end - start < 30 MILLION) {
        for (i = 10 MILLION; i > 0; i--) {};
        end = clock();
    }

    system("date");
    commaOut (end - start, '\n');

    return 0;
}

我的盒子上的输出是:

 Tuesday 17 November  11:53:01 AWST 2015
Tuesday 17 November  11:53:31 AWST 2015
30,001,946

显示比例因子为一百万。如果你运行那个程序,或者调查 CLOCKS_PER_SEC不是 一百万的比例因子,你需要看看其他的东西。


第一步是确保您的代码实际上正在被编译器优化。这意味着,例如,为 --- 设置 -O2-O3 gcc

在我的代码未优化的系统上,我看到:

 Time Cost: 320ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
Time Cost: 300ms
a = 2717999973.760710

它的速度是 -O2 的三倍,尽管答案略有不同,但只有大约百分之一:

 Time Cost: 140ms
Time Cost: 110ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
Time Cost: 100ms
a = 2718000003.159864

这将使这两种情况恢复到同等水平,这是我所期望的,因为 JavaScript 不像过去那样是某种被解释的野兽,在这种情况下,只要看到每个标记就会被解释。

现代 JavaScript 引擎(V8、Rhino 等)可以将代码编译为中间形式(甚至是机器语言),这可能允许与 C 等编译语言大致相同的性能。

但是,老实说,您不会因为速度而选择 JavaScript 或 C++,而是因为它们的优势领域而选择它们。浏览器中没有很多 C 编译器,我也没有注意到很多操作系统和用 JavaScript 编写的嵌入式应用程序。

原文由 paxdiablo 发布,翻译遵循 CC BY-SA 3.0 许可协议

提出了许多优点,其中包括优化标志的影响。然而,我只是想指出,写得不好的代码在任何语言中都会表现得很差,不管它有多“接近金属”。

您的代码以这样一种方式编写,即它会产生一个长的依赖链,任何优化编译器都无法摆脱,除非您明确告诉它忽略严格的算术遵从性。

请注意,过去 10 年中的每个中高端台式机 CPU 的时钟频率为 3-4 Ghz,每个内核每个周期可以计算 2-8 个双精度 FP 指令,从而导致 6-30 GFLOPS 之间的任何地方。这意味着你的 JS 实现达到 1 GFLOPS 的效率只有 3-15%。一个经过适当优化的代码在达到 > 90% 的峰值 FP 时几乎没有问题,这甚至不包括多核并行性。

简而言之,不妨比较一下冒泡排序的效率或其他一些没有人实际使用的效率极低的算法。由于依赖链或复杂的不可预测的逻辑而不必要地触发过多缓存未命中或在管道中造成过多执行停顿的低效代码在任何语言中的执行效果都差不多。

无论如何,使用 –fast-math 编译可能会优化部分链。

原文由 paperclip optimizer 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题