为了在工作中进行演示,我想比较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在做什么。我真的很好奇这里发生的事情的细节。
答案 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代码。