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

Jos*_*shJ 9 c optimization performance node.js

为了在工作中进行演示,我想比较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);
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

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

gcc for.c
./a.out
Run Code Online (Sandbox Code Playgroud)

结果:

2499999950000000
198
Run Code Online (Sandbox Code Playgroud)

然后我在NodeJS中尝试了它:

node for.js
Run Code Online (Sandbox Code Playgroud)

结果:

2499999950000000
116
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

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

Dra*_*rgy 18

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

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

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

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

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

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


G. *_*III 5

添加 register 关键字有助于按预期

#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);
}
Run Code Online (Sandbox Code Playgroud)

并用 C 编译器编译

 cc     for.c   -o for

./for ; node for.js
Run Code Online (Sandbox Code Playgroud)

返回

2499999950000000
97
2499999950000000
222
Run Code Online (Sandbox Code Playgroud)