node.js如何能比c和java更快?比较node.js、c、java和python的基准测试
我做了一个非常简单的基准测试程序,用4种不同的语言计算了10000000个素数node.js如何能比c和java更快?比较node.js、c、java和python的基准测试,java,python,c,node.js,Java,Python,C,Node.js,我做了一个非常简单的基准测试程序,用4种不同的语言计算了10000000个素数 (2.97秒)-node.js(javascript)(4.4.5) (6.96秒)-c(c99) (6.91秒)-java(1.7) (45.5秒)-python(2.7) 以上是平均每次运行3次,用户时间 Node.js是目前运行最快的。这让我感到困惑,原因有两个: javascript总是对变量使用双精度浮点,而c和java在这种情况下使用(长)整数。使用整数的数学应该更快 javascript通常被称为解
- (2.97秒)-node.js(javascript)(4.4.5)
- (6.96秒)-c(c99)
- (6.91秒)-java(1.7)
- (45.5秒)-python(2.7)
public static void main(String[] args) {
long count = 0;
for (long i = 0; i < 10000000; i++){
if (isPrime(i)){
count++;
}
}
System.out.println("total "+count);
}
public static boolean isPrime(long n) {
if (n < 2) return false;
if (n == 2) return true;
if (n == 3) return true;
if (n % 2 == 0) return false;
if (n % 3 == 0) return false;
if (n % 1 > 0) return false;
double sqrtOfN = Math.sqrt(n);
for (long i = 5; i <= sqrtOfN; i += 6){
if (n % i == 0) return false;
if (n % (i + 2) == 0) return false;
}
return true;
};
}
primeCalc.py
linux
附加c运行时间(附录)
- (7.81 s)无优化,gcc primeCalc.c-lm-std=c99-壁
- (8.13 s)优化0,gcc primeCalc.c-lm-O0-std=c99-壁
- (7.30秒)优化1,gcc primeCalc.c-lm-O1-std=c99-壁
- (6.66 s)优化2,gcc primeCalc.c-lm-O2-std=c99-壁
- 每个优化级别用户时间平均3次新运行*
for (long i = 0; i < 100000000; i++) {
d += i >> 1;
d = d / (i +1); // <-- New Term
}
测试6-Cloud9 64位Linux(i=800000001;i<1600000000;i+=10000)
(所有结果均为三次运行的用户秒数平均值,运行之间的时间变化<10%)
结果参差不齐
"use strict";
var isPrime = function(n){
if (n < 2) {return false};
if (n === 2) {return true};
if (n === 3) {return true};
if (n % 2 === 0) {return false};
if (n % 3 === 0) {return false};
var sqrtOfN = Math.sqrt(n);
for (var i = 5; i <= sqrtOfN; i += 6){
if (n % i === 0) {return false}
if (n % (i + 2) === 0) {return false}
}
return true;
};
var countPrime = function(S, E){
var count = 0;
for (let i = S; i < E;i++){
if ( isPrime(i) ) { ++count; }
}
return count;
};
if( process.argv.length != 4) {
console.log('Usage: nodejs count_prime.js <range_start> <range_length>');
process.exit();
}
var S = parseInt(process.argv[2]);
var N = parseInt(process.argv[3]);
var E = S+N;
var P = countPrime(S, E);
console.log('The range [', S, ',', E, ') contains', P, 'primes');
在整数范围内将C和Java数据类型更改为整数大大加快了执行速度。在BBB和Cloud9计算机上,切换到ints使C比node.js快。但在我的Mac上,node.js程序仍然运行得更快。可能是因为Mac使用clang,BBB和Cloud 9计算机使用gcc。有人知道吗如果gcc编译的程序比gcc快
使用所有64位整数时,C在BBB和Cloud9 PC上比node.js快一点,但在MAC上慢一点
您还可以看到,在这些测试中,pypy的速度大约是标准python的四倍
node.js甚至与C兼容的事实让我感到惊讶。我花了几天时间研究了js/V8和C之间的性能差异,首先关注的是V8引擎产生的氢气IR。然而,在确保没有异常优化后,我又回到了对组件的分析t我突然想到答案非常简单,可以归结为关于V8内部的几句话: 根据规范,JavaScript中的所有数字都是64位浮点双精度。不过我们经常使用整数,所以只要有可能,V8就用31位有符号整数表示数字 手边的示例允许以32位拟合所有计算,node.js充分利用了这一点!C代码使用了
long
类型,在OP的(以及我的)平台上,它恰好是64位类型。因此,这是一个32位算术vs 64位算术的问题,主要是由于昂贵的除法/余数运算
如果C代码中的long
替换为int
,那么gcc生成的二进制文件将胜过node.js
此外,如果循环查找32位数字范围之外的素数,node.js版本的性能会显著下降
证明 使用的源代码可以在答案的下面找到 使用C和node.js计算小于1000万的素数
count_primes.js
"use strict";
var isPrime = function(n){
if (n < 2) {return false};
if (n === 2) {return true};
if (n === 3) {return true};
if (n % 2 === 0) {return false};
if (n % 3 === 0) {return false};
var sqrtOfN = Math.sqrt(n);
for (var i = 5; i <= sqrtOfN; i += 6){
if (n % i === 0) {return false}
if (n % (i + 2) === 0) {return false}
}
return true;
};
var countPrime = function(S, E){
var count = 0;
for (let i = S; i < E;i++){
if ( isPrime(i) ) { ++count; }
}
return count;
};
if( process.argv.length != 4) {
console.log('Usage: nodejs count_prime.js <range_start> <range_length>');
process.exit();
}
var S = parseInt(process.argv[2]);
var N = parseInt(process.argv[3]);
var E = S+N;
var P = countPrime(S, E);
console.log('The range [', S, ',', E, ') contains', P, 'primes');
“严格使用”;
var isPrime=函数(n){
如果(n<2){返回false};
如果(n==2){return true};
如果(n==3){return true};
如果(n%2==0){返回false};
如果(n%3==0){返回false};
var sqrtOfN=Math.sqrt(n);
对于(var i=5;i当我使用新算法在python中运行代码时:
real 0m3.583s
user 0m3.297s
sys 0m0.094s
比上面的C基准测试更快。我认为更简单的语言可以帮助您设计更好的算法,但这是我的观点。
(也可以使用多处理来提高速度)
def所有素数(N):
is_prime=[1]*N
#我们知道0和1是复合材料
是_素数[0]=0吗
是_素数[1]=0吗
i=2
#这将从2循环到int(sqrt(x))
当我*我在优化时。事实上,v8是非常优化的。但是,要注意微观基准测试。也许你正在用long
到double
的转换,这些可能对@enRaiser的长时间运行造成成本高昂。在这里,gcc
正在传递-O2
已经-O2-m64丢弃三次跑步的平均时间从6.66秒到6.41秒,但是每次的结果都相差十分之二秒,所以我不能说它真的有什么显著的效果。
$ javac PrimeCalc.java
$ time java PrimeCalc
total 664579
real 0m7.197s
user 0m7.036s
sys 0m0.040s
$ java -version
java version "1.7.0_111"
OpenJDK Runtime Environment (IcedTea 2.6.7) (7u111-2.6.7-0ubuntu0.14.04.3)
OpenJDK 64-Bit Server VM (build 24.111-b01, mixed mode)
import math
def isPrime (n):
if n < 2 : return False
if n == 2 : return True
if n == 3 : return True
if n % 2 == 0 : return False
if n % 3 == 0 : return False
if n % 1 >0 : return False
sqrtOfN = int(math.sqrt(n)) + 1
for i in xrange (5, sqrtOfN, 6):
if n % i == 0 : return False;
if n % (i + 2) == 0 : return False;
return True
count = 0;
for i in xrange(10000000) :
if isPrime(i) :
count+=1
print "total ",count
time python primeCalc.py
total 664579
real 0m46.588s
user 0m45.732s
sys 0m0.156s
$ python --version
Python 2.7.6
$ uname -a
Linux hoarfrost-node_6-3667558 4.2.0-c9 #1 SMP Wed Sep 30 16:14:37 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
for (long i = 0; i < 100000000; i++) {
d += i >> 1;
d = d / (i +1); // <-- New Term
}
language datatype time % to C
javascript auto 3.22 31%
C long 7.95 224%
C int 2.46 0%
Java long 8.08 229%
Java int 2.15 -12%
Python auto 48.43 1872%
Pypy auto 9.51 287%
javascript auto 52.38 12%
C long 46.80 0%
Java long 49.70 6%
Python auto 268.47 474%
Pypy auto 56.55 21%
$ gcc count_primes.c -std=c99 -O3 -lm -o count_primes_long
$ sed 's/long/int/g; s/%li/%i/g' count_primes.c > count_primes_int.c
$ gcc count_primes_int.c -std=c99 -O3 -lm -o count_primes_int
# Count primes <10M using C code with (64-bit) long type
$ time ./count_primes_long 0 10000000
The range [0, 10000000) contains 664579 primes
real 0m4.394s
user 0m4.392s
sys 0m0.000s
# Count primes <10M using C code with (32-bit) int type
$ time ./count_primes_int 0 10000000
The range [0, 10000000) contains 664579 primes
real 0m1.386s
user 0m1.384s
sys 0m0.000s
# Count primes <10M using node.js/V8 which transparently does the
# job utilizing 32-bit types
$ time nodejs ./count_primes.js 0 10000000
The range [ 0 , 10000000 ) contains 664579 primes
real 0m1.828s
user 0m1.820s
sys 0m0.004s
| node.js | C (long)
-----------------------------------
2,000,000,000 | 0.293s | 0.639s # fully within the 32-bit range
-----------------------------------
2,147,383,647 | 0.296s | 0.655s # fully within the 32-bit range
-----------------------------------
2,147,453,647 | 2.498s | 0.646s # 50% within the 32-bit range
-----------------------------------
2,147,483,647 | 4.717s | 0.652s # fully outside the 32-bit range
-----------------------------------
3,000,000,000 | 5.449s | 0.755s # fully outside the 32-bit range
-----------------------------------
"use strict";
var isPrime = function(n){
if (n < 2) {return false};
if (n === 2) {return true};
if (n === 3) {return true};
if (n % 2 === 0) {return false};
if (n % 3 === 0) {return false};
var sqrtOfN = Math.sqrt(n);
for (var i = 5; i <= sqrtOfN; i += 6){
if (n % i === 0) {return false}
if (n % (i + 2) === 0) {return false}
}
return true;
};
var countPrime = function(S, E){
var count = 0;
for (let i = S; i < E;i++){
if ( isPrime(i) ) { ++count; }
}
return count;
};
if( process.argv.length != 4) {
console.log('Usage: nodejs count_prime.js <range_start> <range_length>');
process.exit();
}
var S = parseInt(process.argv[2]);
var N = parseInt(process.argv[3]);
var E = S+N;
var P = countPrime(S, E);
console.log('The range [', S, ',', E, ') contains', P, 'primes');
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define true 1
#define false 0
int isPrime (register long n){
if (n < 2) return false;
if (n == 2) return true;
if (n == 3) return true;
if (n % 2 == 0) return false;
if (n % 3 == 0) return false;
double sqrtOfN = sqrt(n);
for (long i = 5; i <= sqrtOfN; i += 6){
if (n % i == 0) return false;
if (n % (i + 2) == 0) return false;
}
return true;
};
int main(int argc, const char * argv[]) {
if ( argc != 3 ) {
fprintf(stderr, "Usage: count_primes <range_start> <range_length>\n");
exit(1);
}
const long S = atol(argv[1]);
const long N = atol(argv[2]);
register long count = 0;
for (register long i = S; i < S + N; i++){
if ( isPrime(i) ) ++count;
}
printf("The range [%li, %li) contains %li primes\n", S, S+N, count);
}
real 0m3.583s
user 0m3.297s
sys 0m0.094s
def allPrimes(N):
is_prime = [1]*N
# We know 0 and 1 are composites
is_prime[0] = 0
is_prime[1] = 0
i = 2
# This will loop from 2 to int(sqrt(x))
while i*i <= N:
# If we already crossed out this number, then continue
if is_prime[i] == 0:
i += 1
continue
j = 2*i
while j < N:
# Cross out this as it is composite
is_prime[j] = 0
# j is incremented by i, because we want to cover all multiples of i
j += i
i += 1
return is_prime
print("total", sum(allPrimes(10000000)))