어떻게 node.js가 c와 java보다 빠를 수 있습니까?node.js, c, java, python 비교 벤치마크
저는 4개의 다른 언어로 10,000,000까지의 모든 소수를 계산하는 아주 간단한 벤치마킹 프로그램을 만들었습니다.
- (2.97초) - node.js (jav 스크립트) (4.4.5)
- (6.96초) - c(c99)
- (6.91초) - 자바(1.7)
- (45.5초) - 파이썬 (2.7)
위는 각각 평균 3회 실행, 사용자 시간
Node.js가 가장 빠르게 실행됩니다.이것은 두 가지 이유로 저에게 혼란스럽습니다.
- javascript는 변수에 대해 항상 이중 정밀도 플로트를 사용하는 반면 c와 java는 이 경우 (긴) 정수를 사용합니다.정수가 있는 수학은 더 빨라야 합니다.
- just in time 컴파일된 언어일 때 just in time에서 javascript는 종종 해석된 것으로 언급됩니다.하지만 그렇다고 해도 JIT 컴파일러가 어떻게 완전히 컴파일된 언어보다 빠를 수 있겠습니까?파이썬 코드가 가장 느리게 실행되는 것은 놀랄 일도 아니지만, 왜 node.js 코드가 파이썬과 비슷한 속도로 실행되지 않는 것일까요?
-O2 최적화로 c 코드를 컴파일했지만 모든 최적화 수준으로 시도해 보았는데 눈에 띄는 차이가 없었습니다.
Prime.js를 세다
"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 결과
$ time node primeCalc.js
total 664579
real 0m2.965s
user 0m2.928s
sys 0m0.016s
$ node --version
v4.4.5
프라임칼크
#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 결과
$ gcc primeCalc.c -lm -g -O2 -std=c99 -Wall
$ time ./a.out
total 664579
real 0m6.718s
user 0m6.668s
sys 0m0.008s
프라임칼크자바
퍼블릭 클래스 프라임칼크 {
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;
};
}
자바 결과
$ 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
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
추가 크럼 시간(부록)
- (7.81초) 최적화 없음, gcc primeCalc.c - lm - std=c99 - 벽
- (8.13초) 최적화 0, gcc primeCalc.c - lm - O0 - std=c99 - 벽
- (7.30초) 최적화 1, gcc primeCalc.c - lm - O1 - std=c99 - 벽
(6.66초) 최적화 2, gcc primeCalc.c - lm - O2 - std=c99 - 벽
- 각 최적화 레벨 사용자 시간마다 평균 3회 새로운 실행 *
여기 게시물을 읽었습니다.이 NodeJS가 네이티브 C보다 2배 빠른 이유는 무엇입니까?이 코드는 실제로 중요한 일을 하지 않는 예제를 사용합니다.마치 컴파일러가 컴파일 시간에 결과를 파악할 수 있고 답을 도출하기 위해 루프를 1000000번 실행할 필요도 없는 것 같습니다.계산에 다른 분할 단계를 추가하면 최적화는 훨씬 덜 중요합니다.
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의 답변을 읽고 몇 가지 검증 테스트를 진행했습니다.
검정 1 - 32비트 비글본 블랙, 664,579개의 소수점, 최대 10,000,000개
32비트 프로세서를 가진 비글본 블랙에서 실행되는 편집되지 않은 calcalPrime.js 및 calcalPrime.c.
- C 코드 = 62초 (gcc, 긴 데이터 타입)
- JS 코드 = 102초 (노드 v4)
테스트 2 - 64 비트 맥북 프로, 664,579 primes ~ 10,000,000
calcPrime.c 코드의 긴 데이터 유형을 uint32_t로 교체하고 64비트 프로세서가 있는 맥북 프로에서 실행합니다.
- C 코드 = 5.73초 (clang, long data type)
- C 코드 = 2.43초 (clang, uint_32_t data type
- JS 코드 = 2.12초 (노드 v4)
테스트 3 - 64비트 맥북 프로, 91,836 primes (i=1; i < 8,000,000,000; i+=10000)
C 코드에서 부호 없는 긴 데이터 형식을 사용하고, 자바스크립트가 64비트를 사용하도록 강제합니다. - C 코드 = 20.4초 (clang, long data 형식) - JS 코드 = 17.8초 (node v4)
테스트 4 - 64비트 맥북 프로, 86,277개 소수 (i = 8,000,00,001; i < 16,000,000; i+=10000)
C 코드에서 부호 없는 긴 데이터 형식을 사용하고, 자바스크립트가 64비트를 모두 사용하도록 강제합니다. - C 코드 = 35.8초 (clang, long data 형식) - JS 코드 = 34.1초 (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 = 80000001, 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%입니다.
혼합 결과
정수 범위에 있을 때 C 및 Java 데이터 유형을 정수로 변경하면 실행 속도가 크게 빨라집니다.BBB와 Cloud9 컴퓨터에서 int로 전환하면 node.js보다 C가 더 빠릅니다.하지만 제 Mac에서는 node.js 프로그램이 더 빨리 실행되었습니다.아마도 맥은 클랑을 사용하고 있고 BBB와 클라우드 9 컴퓨터는 gcc를 사용하고 있기 때문일 것입니다.gcc가 gcc보다 더 빠른 프로그램을 컴파일하는지 아는 사람?
64비트 정수 C를 모두 사용했을 때는 BBB와 Cloud9 PC에서는 node.js보다 조금 빨랐지만 MAC에서는 조금 느렸습니다.
또한 이 테스트에서 파이피가 표준 파이썬보다 약 4배 빠르다는 것을 알 수 있습니다.
node.js가 C와 호환된다는 사실이 놀랍습니다.
저는 며칠 동안 V8 엔진에서 발생하는 Hydrogen IR을 중심으로 JS/V8과 C의 성능 차이를 조사했습니다.하지만, 특별한 최적화 기능이 없다는 것을 확인한 후, 조립 결과 분석으로 돌아갔고, 그 답이 매우 간단하다는 것을 알게 되었습니다. V8의 내부 자료에 대한 Jay Conrod의 블로그 게시물에 있는 몇 개의 문장으로 요약됩니다.
스펙에 따르면 자바스크립트의 모든 숫자는 64비트 부동 소수점 두 배입니다.우리는 정수를 자주 사용하기 때문에 V8은 가능할 때마다 31비트 부호 정수로 숫자를 표시합니다.
당면한 예제는 모든 계산을 32비트로 맞출 수 있으며 node.js는 이를 최대한 활용합니다!C 코드는 다음을 활용합니다.long
OP(나의 플랫폼뿐만 아니라) 플랫폼에서 64비트 유형이 되는 유형입니다.따라서 32비트 산술 대 64비트 산술 문제인데, 대부분 비용이 많이 드는 분할/잔여 연산 때문입니다.
한다면long
C 코드는 다음으로 대체됩니다.int
, 그러면 gcc가 node.js를 능가하는 바이너리.
또한 루프가 32비트 숫자의 영역 밖에 있는 범위에서 소수를 찾도록 만들어지면 node.js 버전의 성능이 크게 떨어집니다.
증명
사용된 소스 코드는 결과 아래의 답변에서 더 확인할 수 있습니다.
C와 node.js로 천만 미만의 소수를 세는 것
$ 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 범위의 소수를 세는 것:
| 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);
}
새 알고리즘으로 파이썬에서 코드를 실행했을 때:
real 0m3.583s
user 0m3.297s
sys 0m0.094s
위의 C 벤치마크보다 더 빠릅니다.언어가 단순하면 알고리즘을 더 잘 설계할 수 있다고 생각하지만, 그것이 제 생각입니다. (또한 다중 처리를 사용하여 훨씬 더 빠르게 만들 수 있습니다.)
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)))
언급URL : https://stackoverflow.com/questions/39360403/how-can-node-js-be-faster-than-c-and-java-benchmark-comparing-node-js-c-java
'programing' 카테고리의 다른 글
org.springframework.context 형식입니다.구성 가능한 ApplicationContext를 확인할 수 없습니다.필요한 .class 파일에서 간접적으로 참조됩니다. (0) | 2023.09.28 |
---|---|
AngularJS - $q.all()에서 오류 복원력 (0) | 2023.09.28 |
ngThumb 지시어에서 AngularJS 파일 업로드(angular-file-uppload 포함) (0) | 2023.09.28 |
mysql의 문자열에서 숫자만 가져오는 방법? (0) | 2023.09.28 |
점 확대(척도 및 변환 사용) (0) | 2023.09.28 |