2013-06-11 3 views
17

लंबे समय तक, मैंने जावास्क्रिप्ट की तुलना में सी ++ के बारे में सोचा है। हालांकि, आज मैंने दो भाषाओं में फ्लोटिंग पॉइंट गणना की गति की तुलना करने के लिए एक बेंचमार्क स्क्रिप्ट बनाई और परिणाम अद्भुत है!जावास्क्रिप्ट सी ++ से 4 गुना तेज है?

जावास्क्रिप्ट सी ++ से लगभग 4 गुना तेज है!

मैं दोनों भाषाओं को अपने i5-430M लैपटॉप पर एक ही काम करने देता हूं, 100000000 बार के लिए a = a + b प्रदर्शन करता हूं। सी ++ में लगभग 410 एमएस लगता है, जबकि जावास्क्रिप्ट में केवल 120 एमएस लगता है।

मुझे वास्तव में कोई विचार नहीं है कि इस मामले में जावास्क्रिप्ट इतनी तेजी से क्यों चल सकता है। क्या कोई इसे समझा सकता है?

कोड मैं जावास्क्रिप्ट (NodeJS के साथ चलाने के) के लिए इस्तेमाल किया जाता है:

(function() { 
    var a = 3.1415926, b = 2.718; 
    var i, j, d1, d2; 
    for(j=0; j<10; j++) { 
     d1 = new Date(); 
     for(i=0; i<100000000; i++) { 
      a = a + b; 
     } 
     d2 = new Date(); 
     console.log("Time Cost:" + (d2.getTime() - d1.getTime()) + "ms"); 
    } 
    console.log("a = " + a); 
})(); 

और C++ (छ ++ द्वारा संकलित) के लिए कोड है:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double a = 3.1415926, b = 2.718; 
    int i, j; 
    clock_t start, end; 
    for(j=0; j<10; j++) { 
     start = clock(); 
     for(i=0; i<100000000; i++) { 
      a = a + b; 
     } 
     end = clock(); 
     printf("Time Cost: %dms\n", (end - start) * 1000/CLOCKS_PER_SEC); 
    } 
    printf("a = %lf\n", a); 
    return 0; 
} 
+0

नहीं, मैं बस g ++ xxx.cpp कमांड का उपयोग करता हूं। अनुकूलित करने के लिए मैं किस पैरामीटर का उपयोग करूं? मैं सीपीपी से काफी परिचित नहीं हूँ। – streaver91

+7

कृपया '-O3 -ffast-Math' जोड़ें और देखें कि C++ समय के साथ क्या होता है। –

+8

* "लंबे समय तक, मुझे हमेशा लगता है कि सी ++ जावास्क्रिप्ट से तेज़ होना चाहिए।" * आप समझते हैं कि जावास्क्रिप्ट इंजन आमतौर पर सी ++ – jamylak

उत्तर

143

मैं कुछ बुरी खबर हो सकती है आपके लिए यदि आप लिनक्स सिस्टम पर हैं (जो कम से कम इस स्थिति में POSIX का अनुपालन करता है)। clock() प्रोग्राम द्वारा खपत घड़ी की घड़ी की कॉल रिटर्न संख्या और CLOCKS_PER_SEC द्वारा स्केल किया गया, जो 1,000,000 है।

इसका मतलब है कि, अगर आप एक ऐसी प्रणाली पर हैं, तो आप सी के लिए माइक्रोसेकंड और मिलीसेकेंड जावास्क्रिप्ट के लिए में बात कर रहे हैं (JS online docs के अनुसार)। तो, जेएस की तुलना में चार गुना तेजी से, सी ++ वास्तव में 250 गुना तेज है।

अब यह आप को देखने के लिए आपके सिस्टम पर निम्नलिखित कार्यक्रम चला सकते हैं अगर यह एक ही मूल्य से बढ़ाया है, हो सकता है कि आप एक प्रणाली पर हैं जहां CLOCKS_PER_SECOND एक लाख से कुछ अन्य है:

#include <stdio.h> 
#include <time.h> 
#include <stdlib.h> 

#define MILLION * 1000000 

static void commaOut (int n, char c) { 
    if (n < 1000) { 
     printf ("%d%c", n, c); 
     return; 
    } 

    commaOut (n/1000, ','); 
    printf ("%03d%c", n % 1000, c); 
} 

int main (int argc, char *argv[]) { 
    int i; 

    system("date"); 
    clock_t start = clock(); 
    clock_t end = start; 

    while (end - start < 30 MILLION) { 
     for (i = 10 MILLION; i > 0; i--) {}; 
     end = clock(); 
    } 

    system("date"); 
    commaOut (end - start, '\n'); 

    return 0; 
} 

मेरे बॉक्स पर आउटपुट है:

Tuesday 17 November 11:53:01 AWST 2015 
Tuesday 17 November 11:53:31 AWST 2015 
30,001,946 

दिखा रहा है कि स्केलिंग कारक एक लाख है। यदि आप उस प्रोग्राम को चलाते हैं, या CLOCKS_PER_SEC की जांच करते हैं और यह एक मिलियन का स्केलिंग कारक नहीं है, तो आपको कुछ अन्य चीजों को देखने की आवश्यकता है।


पहला चरण यह सुनिश्चित करना है कि आपका कोड वास्तव में संकलक द्वारा अनुकूलित किया जा रहा है। इसका मतलब है, उदाहरण के लिए, के लिए -O2 या -O3 सेट करना।

unoptimised कोड के साथ अपने सिस्टम पर, मैं देख रहा हूँ:

Time Cost: 320ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
Time Cost: 300ms 
a = 2717999973.760710 

और यह, -O2 साथ तेजी से तीन बार है एक अलग जवाब के साथ यद्यपि, हालांकि केवल एक प्रतिशत के बारे में दस लाखवाँ द्वारा:

Time Cost: 140ms 
Time Cost: 110ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
Time Cost: 100ms 
a = 2718000003.159864 

इससे दोनों स्थितियों को एक दूसरे के बराबर बराबर लाया जाएगा, कुछ ऐसा जो मैं उम्मीद करता हूं क्योंकि जावास्क्रिप्ट पुराने दिनों में कुछ व्याख्याित जानवर नहीं है, जहां प्रत्येक टोकन का अर्थ जब भी देखा जाता है।

आधुनिक जावास्क्रिप्ट इंजन (वी 8, राइनो, आदि) (या यहां तक ​​कि मशीन भाषा के लिए) एक मध्यवर्ती फार्म के लिए कोड संकलन कर सकते हैं जो प्रदर्शन मोटे तौर पर सी

तरह संकलित भाषाओं

लेकिन साथ बराबर अनुमति दे सकता है, ईमानदार होना , आप इसकी गति के लिए जावास्क्रिप्ट या सी ++ चुनने की कोशिश नहीं करते हैं, आप उन्हें अपने ताकत के क्षेत्रों के लिए चुनते हैं। ब्राउज़र के अंदर चारों ओर तैरने वाले कई सी कंपाइलर नहीं हैं और मैंने कई ऑपरेटिंग सिस्टम और जावास्क्रिप्ट में लिखे गए एम्बेडेड ऐप्स को नहीं देखा है।

+17

मैन। आपने हमें बचाया! –

+1

मुझे लगता है कि यह मामला नहीं है, 400ms कुछ महसूस करना आसान है। आउटपुट जावास्क्रिप्ट से वास्तव में धीमा प्रतीत होता है। – streaver91

+0

@ user2189264, शायद यह शुरू करने और प्रक्रिया को फाड़ने के लिए समय की मात्रा लेता है। मैं "प्रमाण" दिखाने के लिए अद्यतन करूंगा। – paxdiablo

6

ऑप्टिमाइज़ेशन को चालू करने के साथ त्वरित परीक्षण करना, मुझे एक प्राचीन एएमडी 64 एक्स 2 प्रोसेसर के लिए लगभग 150 एमएस और एक उचित हाल ही में इंटेल i7 प्रोसेसर के लिए लगभग 9 0 एमएस का परिणाम मिला।

फिर मैंने एक कारण के बारे में कुछ विचार देने के लिए कुछ और किया जो आप सी ++ का उपयोग करना चाहेंगे। मैं पाश के चार पुनरावृत्तियों, इस पाने के लिए unrolled:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double a = 3.1415926, b = 2.718; 
    double c = 0.0, d=0.0, e=0.0; 
    int i, j; 
    clock_t start, end; 
    for(j=0; j<10; j++) { 
     start = clock(); 
     for(i=0; i<100000000; i+=4) { 
      a += b; 
      c += b; 
      d += b; 
      e += b; 
     } 
     a += c + d + e; 
     end = clock(); 
     printf("Time Cost: %fms\n", (1000.0 * (end - start))/CLOCKS_PER_SEC); 
    } 
    printf("a = %lf\n", a); 
    return 0; 
} 

यह सी ++ 44ms के बारे में एएमडी पर में कोड को चलने देने के (इंटेल पर इस संस्करण को चलाने के लिए भूल गया)। तब मैंने कंपाइलर के ऑटो-वेक्टरिज़र (-कपर + वीसी ++ के साथ) चालू कर दिया। इससे थोड़ी और समय कम हो गई, एएमडी पर लगभग 40 एमएस और इंटेल पर 30 एमएस कम हो गया।

नीचे पंक्ति: यदि आप सी ++ का उपयोग करना चाहते हैं, तो आपको वास्तव में संकलक का उपयोग करने का तरीका सीखना होगा। यदि आप वास्तव में अच्छे परिणाम प्राप्त करना चाहते हैं, तो आप शायद बेहतर कोड लिखना सीखना चाहते हैं।

मुझे जोड़ना चाहिए: मैंने जावास्क्रिप्ट के तहत एक संस्करण को अनलॉक लूप के साथ परीक्षण करने का प्रयास नहीं किया था। ऐसा करने से जेएस में भी एक समान (या कम से कम कुछ) गति सुधार प्रदान हो सकता है। व्यक्तिगत रूप से, मुझे लगता है कि जावास्क्रिप्ट को सी ++ से तुलना करने से कोड को तेज़ बनाना बहुत दिलचस्प है।

यदि आप इस तरह के कोड को तेजी से चलाने के लिए चाहते हैं, तो लूप को अनलोल करें (कम से कम सी ++ में)।

समानांतर कंप्यूटिंग के विषय के बाद से, मैंने सोचा कि मैं ओपनएमपी का उपयोग करके एक और संस्करण जोड़ूंगा। जब मैं उस पर था, मैंने कोड को थोड़ा सा साफ़ कर दिया, इसलिए मैं क्या चल रहा था इसका ट्रैक रख सकता था। मैंने भीतरी कोड को थोड़ा सा बदल दिया, आंतरिक लूप के प्रत्येक निष्पादन के लिए समय के बजाय समग्र समय प्रदर्शित करने के लिए। जिसके परिणामस्वरूप कोड इस तरह देखा:

#include <stdio.h> 
#include <ctime> 

int main() { 
    double total = 0.0; 
    double inc = 2.718; 
    int i, j; 
    clock_t start, end; 
    start = clock(); 

    #pragma omp parallel for reduction(+:total) firstprivate(inc) 
    for(j=0; j<10; j++) { 
     double a=0.0, b=0.0, c=0.0, d=0.0; 
     for(i=0; i<100000000; i+=4) { 
      a += inc; 
      b += inc; 
      c += inc; 
      d += inc; 
     } 
     total += a + b + c + d; 
    } 
    end = clock(); 
    printf("Time Cost: %fms\n", (1000.0 * (end - start))/CLOCKS_PER_SEC); 

    printf("a = %lf\n", total); 
    return 0; 
} 

प्राथमिक इसके अलावा यहां निम्नलिखित (वैसे कुछ हद तक रहस्यमय) लाइन है:

#pragma omp parallel for reduction(+:total) firstprivate(inc) 

इस संकलक बताता है एक से अधिक थ्रेड में बाहरी पाश निष्पादित करने के लिए एक साथ, प्रत्येक थ्रेड के लिए inc की अलग प्रति, और समांतर अनुभाग के बाद total के व्यक्तिगत मानों को एक साथ जोड़ना।

परिणाम इस बारे में है कि आप शायद क्या उम्मीद करेंगे। यदि हम कंपाइलर के -openmp ध्वज के साथ ओपनएमपी को सक्षम नहीं करते हैं, तो रिपोर्ट समय लगभग 10 गुणा है जिसे हमने पहले व्यक्तिगत निष्पादन के लिए देखा था (एएमडी के लिए 40 9 एमएस, इंटेल के लिए 323 एमएस)। ओपनएमपी चालू होने के साथ, एएमडी के लिए समय 217 एमएस और इंटेल के लिए 100 एमएस तक गिर जाता है।

तो, इंटेल पर मूल संस्करण ने बाहरी लूप के एक पुनरावृत्ति के लिए 9 0 मिमी लिया। इस संस्करण के साथ हम बाहरी लूप के सभी 10 पुनरावृत्तियों के लिए थोड़ी देर (100 एमएस) प्राप्त कर रहे हैं - लगभग 9: 1 की गति में सुधार। अधिक कोर वाले मशीन पर, हम और भी सुधार की उम्मीद कर सकते हैं (ओपनएमपी आमतौर पर सभी उपलब्ध कोरों का लाभ उठाएगा, हालांकि यदि आप चाहें तो थ्रेड की संख्या मैन्युअल रूप से ट्यून कर सकते हैं)।

+0

कूल! स्पष्टांतरांतर कोड के बिना समांतर कंप्यूटिंग – streaver91

+2

@ user2189264: हाँ और नहीं - यह अभी भी एक कोर में निष्पादित है। थोड़ी अधिक काम के साथ (कुछ ओपनएमपी निर्देश, उदाहरण के लिए) हम इसे कई कोरों पर भी निष्पादित कर सकते हैं, प्रभावी ढंग से गति को फिर से गुणा कर सकते हैं। मैंने अभी तक बहुत कुछ किया है, हालांकि इसे एक कोर पर संसाधनों का बेहतर उपयोग करने दिया जाता है (खुला निर्देश स्तर समांतरता, थ्रेड-स्तर समांतरता नहीं)। –

0

यह एक ध्रुवीकरण विषय है, इसलिए एक पर एक नजर है हो सकता है:

http://benchmarksgame.alioth.debian.org/

बेंचमार्किंग भाषाओं के सभी प्रकार के।

जावास्क्रिप्ट वी 8 और उदाहरण के तौर पर, उदाहरण के रूप में सरल लूप के लिए निश्चित रूप से अच्छा काम कर रहे हैं, शायद बहुत ही समान मशीन कोड उत्पन्न करना। अधिकांश "उपयोगकर्ता के नजदीक" अनुप्रयोगों के लिए जावास्क्रिप्ट निश्चित रूप से बेहतर विकल्प है, लेकिन अधिक जटिल एल्गोरिदम/अनुप्रयोगों के लिए स्मृति अपशिष्ट और कई बार अपरिहार्य प्रदर्शन हिट (और नियंत्रण की कमी) को ध्यान में रखें।

संबंधित मुद्दे