为什么这个NodeJS比本机C快2倍?

时间:2014-12-11 21:44:11

标签: c node.js performance optimization

为了在工作中进行演示,我想比较NodeJS和C的性能。这是我写的:

Node.js(for.js):

var d = 0.0,
    start = new Date().getTime();

for (var i = 0; i < 100000000; i++)
{
  d += i >> 1;
}

var end = new Date().getTime();

console.log(d);
console.log(end - start);

C(for.c)

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

int main () {
  clock_t start = clock();

  long d = 0.0;

  for (long i = 0; i < 100000000; i++)
  {
    d += i >> 1;    
  }

  clock_t end = clock();
  clock_t elapsed = (end - start) / (CLOCKS_PER_SEC / 1000); 

  printf("%ld\n", d);
  printf("%lu\n", elapsed);
}

使用GCC我编译了我的for.c并运行它:

gcc for.c
./a.out

结果:

2499999950000000
198

然后我在NodeJS中尝试了它:

node for.js

结果:

2499999950000000
116

经过多次运行后,我发现无论如何都是如此。如果我在循环中切换for.c以使用double而不是long,那么C花费的时间就更长了!

没有尝试开始火焰战,但为什么Node.JS(116毫秒)在执行同样的操作时比原生C(198毫秒)快得多? Node.JS是否应用了GCC不能开箱即用的优化?

修改

根据评论中的建议,我跑了gcc -Wall -O2 for.c。结果改善为C需要29毫秒。这就引出了一个问题,原生C设置如何不像Javascript编译器那样优化?另外,-Wall和-02在做什么。我真的很好奇这里发生的事情的细节。

4 个答案:

答案 0 :(得分:16)

这就引出了一个问题,原生C设置如何不像Javascript编译器那样优化?

由于C是静态编译和链接的,因此需要整个代码库的可能冗长的构建步骤(我曾经在一个完全优化的构建花了差不多一个小时,但是只有10分钟),并且非常危险如果你不小心对待它,那么硬件级语言可能会冒很多未定义的行为,编译器的默认设置通常不会优化到smithereens,因为这是一个开发人员/调试版本,旨在更快地帮助调试和提高工作效率周转。

因此,在C语言中,您可以在未优化但更快构建,更易于调试的开发人员/调试构建与非常优化,更慢构建,更难实现之间实现明显区分。调试生产/发布构建,运行速度非常快,编译器的默认设置通常有利于前者。

使用类似v8 / NodeJS的东西,您正在处理即时编译器(动态编译),它在运行时即时构建和优化必要的代码。最重要的是,JS是一种更安全的语言,并且通常还设计用于安全性,不允许您使用硬件的原始位和字节。

因此,它不需要像C / C ++这样的本地静态编译语言的强大的发布/调试构建区别。但是如果你真的想要的话,它也不会让你像在C中一样把踏板踩到金属上。

很多人试图对来自其他语言的C / C ++进行基准测试,往往无法理解这种构建的区别以及编译器/链接器优化设置的重要性并使其混淆。正如您所看到的,通过适当的设置,很难超越这些本机编译器和语言的性能,使您能够编写真正的低级代码。

答案 1 :(得分:2)

添加注册关键字有助于预期

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

int main () {
  register long i, d;
  clock_t start = clock();
  i = d = 0L;

  for (i = 0; i < 100000000L; i++) {
    d += i >> 1;
  }

  clock_t end = clock();
  clock_t elapsed = (end - start) / (CLOCKS_PER_SEC / 1000);

  printf("%ld\n", d);
  printf("%lu\n", elapsed);
}

并使用C编译器进行编译

 cc     for.c   -o for

./for ; node for.js

返回

2499999950000000
97
2499999950000000
222

答案 2 :(得分:1)

我还做了一些计算质数的测试,我发现Node.js的速度是C see here的两倍。

当你有一个非常简单的计数类型的循环时,-O2优化有时可以将输出转换为简单的公式,甚至不需要迭代循环。有关详细信息,请参阅Karl's Blog。如果你在例程中添加更复杂的东西,那么node.js可能会再次更快。例如,我在您的示例程序中添加了一个devisor术语,并且c -O2优化不再能够将其转换为简单的公式并且node.js再次变得更快。

我仍然感到困惑的是,在简单的整数计算中,node.js如何比c更接近,但在我迄今为止所做的每一次测试中,它都更快。我还进行了一些我尚未发布的按位计算测试,但node.js仍然更快。

答案 3 :(得分:0)

node.js和C的不同之处在于,node.js在解释JavaScript,而C在将代码编译为机器语言。因此,两者的处理方式不同。对于node.js,您只需运行.js文件。 C与此大不相同。使用GCC将代码编译为机器语言时,必须提供编译器优化设置(也称为“标志”)。如果为GCC指定-O3标志,则您的node.js程序实际上比C程序慢。实际上,node.js程序花费的时间是C程序的两倍。您说过,您想了解有关C编译器如何优化代码的更多信息。这是一个复杂的主题/领域,我强烈建议阅读this Wikipedia article的编译器优化知识以了解更多信息。

简而言之,您进行了不公平的比较,因为您没有优化C代码。