node.js如何比c和java更快?基准比较node.js,c,java和python [英] How can node.js be faster than c and java? Benchmark comparing node.js, c, java and python

查看:185
本文介绍了node.js如何比c和java更快?基准比较node.js,c,java和python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个非常简单的基准测试程序,用4种不同语言计算高达10,000,000的所有素数。

I made a very simple benchmarking program that calculates all the prime numbers up to 10,000,000 in 4 different languages.


  • (2.97秒) - node.js(javascript)(4.4.5)

  • ( 6.96秒) - c(c99)

  • (6.91秒) - java(1.7)

  • (45.5秒) - python(2.7)

  • (2.97 seconds) - node.js (javascript) (4.4.5)
  • (6.96 seconds) - c (c99)
  • (6.91 seconds) - java (1.7)
  • (45.5 seconds) - python (2.7)

以上是平均每次3次运行,用户时间

Node.js运行速度最快。这让我感到困惑有两个原因:

Node.js runs by far the fastest. This is confusing to me for two reasons:


  1. javascript总是使用双精度浮点数作为变量而c和java正在使用(长)整数这个案例。带整数的数学应该更快。

  2. javascript通常被称为解释,实际上它是一种及时编译的语言。但即便如此,JIT编译器如何比完全编译的语言更快?
    python代码运行速度最慢,这并不奇怪,但为什么node.js代码的运行速度与python类似?

我用-O2优化编译了c代码,但我尝试了所有级别的优化,并没有产生显着的差异。

I compiled the c code with -O2 optimization, but I tried it with all levels of optimization and it didn't make a noticeable difference.

"use strict";

var isPrime = function(n){
    //if (n !== parseInt(n,10)) {return false};
    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) {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(){
    var count = 0;
    for (let i = 1; i < 10000000;i++){
        if (isPrime(i)){
            count++;
        }
    }
    console.log('total',count);
};

countPrime();



node.js results



node.js results

$ time node primeCalc.js
total 664579

real    0m2.965s
user    0m2.928s
sys     0m0.016s

$ node --version
v4.4.5



primeCalc.c



primeCalc.c

#include <stdio.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;
    if (n % 1)      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[]) {
    register long count = 0;
    for (register long i = 0; i < 10000000; i++){
        if (isPrime(i)){
            count++;
        }
    }

    printf("total %li\n",count);
    return 0;
}



c结果



c results

$ gcc primeCalc.c -lm -g -O2 -std=c99 -Wall
$ time ./a.out
total 664579
real    0m6.718s
user    0m6.668s
sys     0m0.008s



PrimeCalc.java



公共类PrimeCalc {

PrimeCalc.java

public class PrimeCalc {

  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;
  };

}



java结果



java results

 $ 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)



primeCalc.py



primeCalc.py

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



python results



python results

time python primeCalc.py
total  664579
real    0m46.588s
user    0m45.732s
sys     0m0.156s 
$ python --version
Python 2.7.6 



linux



linux

$ 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



额外的c运行时间(附录)




  • (7.81秒)没有优化,gcc primeCalc.c -lm -std = c99 -Wall

  • (8.13 s)优化0,gcc primeCalc.c -lm -O0 -std = c99 - Wall

  • (7.30秒)优化1,gcc primeCalc.c -lm -O1 -std = c99 -Wall

  • (6.66 s )优化2,gcc primeCalc.c -lm -O2 -std = c99 -Wall

    additional c run times (addendum)

    • (7.81 s) no optimization, gcc primeCalc.c -lm -std=c99 -Wall
    • (8.13 s) optimization 0, gcc primeCalc.c -lm -O0 -std=c99 -Wall
    • (7.30 s) optimization 1, gcc primeCalc.c -lm -O1 -std=c99 -Wall
    • (6.66 s) optimization 2, gcc primeCalc.c -lm -O2 -std=c99 -Wall


      • 平均每次优化3次新运行离子水平用户时间*

      我在这里阅读帖子:
      为什么这个NodeJS 2x比原生C快?
      此代码使用的实例实际上并没有做任何重要的事情。就好像编译器可以在编译时找出结果,甚至不需要执行循环100000000次来得出答案。
      如果在计算中添加另一个除法步骤,则优化的重要性要小得多。

      I read the post here: Why is this NodeJS 2x faster than native C? This code uses an example that doesn't actually do anything significant. It's as if the compiler can figure out the result at compile time and it doesn't even need to execute the loop 100000000 times to come up with the answer. If one adds another division step to the calculation the optimization is much less significant.

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




      • ( 1.88秒)没有优化

      • (1.53秒)优化(-O2)

      • 更新03/15/2017
        阅读@leon的答案后,我进行了一些验证测试。

        Update 03/15/2017 After reading the answer from @leon I ran a few verification tests.

        测试1 - 32位Beaglebone Black,664,579素数高达10,000,000

        未经编辑的calcPrime.js和calcPrime.c正在运行在具有32位处理器的Beaglebone black上。

        Unedited calcPrime.js and calcPrime.c running on the Beaglebone black which has a 32 bit processor.


        • C代码= 62秒(gcc,长数据类型)

        • JS代码= 102秒(节点v4)

        测试2 - 64位Macbook Pro,664,579素数高达10,000,000

        使用uint32_t替换calcPrime.c代码中的长数据类型,并在具有64位处理器的MacBook pro上运行。

        Replace long datatypes in calcPrime.c code with uint32_t and running on my MacBook pro which has a 64 bit processor.


        • C代码= 5.73秒(clang,长数据类型)

        • C代码= 2.43 s econds(clang,uint_32_t数据类型)

        • JS代码= 2.12秒(节点v4)

        测试3 - 64位Macbook Pro,91,836个素数(i = 1;我< 80亿; i + = 10000)

        在C代码中使用无符号长数据类型,强制javascript使用64位。
        - C代码= 20.4秒(clang,long数据类型)
        - JS代码= 17.8秒(节点v4)

        Use unsigned long datatypes in C code, force javascript to use some 64 bit. - C code = 20.4 seconds (clang, long datatype) - JS code = 17.8 seconds (node v4)

        测试4 - 64位Macbook Pro,86,277个素数(i = 8,000,00,001; i <16,000,000,000; i + = 10000)

        在C代码中使用无符号长数据类型,强制javascript使用所有64位。
        - C代码= 35.8秒(clang,long数据类型)
        - JS代码= 34.1秒(节点v4)

        Use unsigned long datatypes in C code, force javascript to use all 64 bit. - C code = 35.8 seconds (clang, long datatype) - JS code = 34.1 seconds (node v4)

        测试5 - Cloud9 64位Linux,(i = 0; i <10000000; i ++)

        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%
        

        测试6 - Cloud9 64位Linux,(i = 8000000001; i <16000000000; i + = 10000)

        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%
        

        (所有结果均为用户的平均值秒数三次运行,运行之间的时间变化< 10%)

        (All results are the average of the user seconds for three runs, time variation between runs < 10%)

        混合结果

        将C和Java数据类型更改为整数当在整数范围内显着加快执行速度。在BBB和Cloud9计算机上切换到int使得C比node.js更快。但是在我的Mac上,node.js程序仍然运行得更快。也许是因为Mac正在使用clang而BBB和Cloud 9计算机正在使用gcc。有没有人知道gcc是否编译比gcc更快的程序?

        Changing the C and Java datatype to integer when in the range of integers significantly sped up execution. On the BBB and Cloud9 computers switching to ints made C faster than node.js. But on my Mac the node.js program still ran faster. Perhaps because the Mac is using clang and the BBB and Cloud 9 computers are using gcc. Does anyone know if gcc compiles faster programs than gcc?

        当使用所有64位整数时,C比BBB和Cloud9 PC上的node.js快一点但有点快在我的MAC上慢一点。

        When using all 64 bit integers C was a bit faster than node.js on the BBB and Cloud9 PC but a little slower on my MAC.

        在这些测试中,您还可以看到pypy比标准python快四倍。

        You can also see that pypy is about four times faster than standard python in these tests.

        node.js甚至与C兼容的事实让我感到惊讶。

        The fact that node.js is even compatible to C amazes me.

        推荐答案

        我花了几天时间调查JS / V8和C之间的性能差异,首先集中在V8发动机产生的氢气IR上。然而,在确保那里没有非常优化之后,我回到了对程序集输出的分析,它让我觉得答案很简单,在 Jay Conrod关于V8内幕的博客文章

        I spent a couple of days investigating the performance difference between JS/V8 and C, focusing first of all on the Hydrogen IR generated by the V8 engine. However, after making sure that no extraordinary optimizations are present there, I got back to the analysis of the assembly output and it struck me that the answer was a very simple one, boiling down to the couple of sentences in Jay Conrod's blog post on internals of V8:


        根据规范,JavaScript中的所有数字都是64位浮点数双精度数。我们经常使用整数,因此 V8表示尽可能使用31位有符号整数的数字

        According to the spec, all numbers in JavaScript are 64-bit floating point doubles. We frequently work with integers though, so V8 represents numbers with 31-bit signed integers whenever possible.

        手边的例子允许以32位和node.js拟合所有计算,充分利用它! C代码使用 long 类型,它在OP(以及我的)平台上恰好是64位类型。因此,它是一个32位算术与64位算术问题,主要是由于昂贵的除法/余数运算。

        The example at hand allows fitting all computations in 32 bits and node.js takes full advantage of that! The C code utilizes the long type, which on OP's (as well as my) platform happens to be a 64-bit type. Thus, it is a 32-bit arithmetic vs 64-bit arithmetic issue, mostly due to the expensive division/remainder operation.

        如果 long < C代码中的/ code>替换为 int ,然后由gcc生成的二进制文件beats node.js。

        If long in the C code is replaced with int, then the binary produced by gcc beats node.js.

        此外,如果循环用于查找超出32位数字范围的质数,则node.js版本的性能会显着下降。

        Also, if the loop is made to look for primes over a range that is outside the realm of 32-bit numbers the performance of the node.js version drops significantly.

        在结果下方的答案中可以找到使用过的源代码。

        The used source code is found further in the answer, below the results.


        使用C和node.js计算小于1000万的素数




        $ 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
        




        在签名的32位整数限制附近的性能数据


        从第一列中包含的数字开始计算长度为100,000的素数:

        Counting the primes in the range of length 100,000 starting at the number contained in the first column:

                      | 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
        -----------------------------------
        






        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');
        






        count_primes.c

        #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);
        }
        

        这篇关于node.js如何比c和java更快?基准比较node.js,c,java和python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆