2012-04-12 17 views
10

तो, मैं एक 2 डी जावास्क्रिप्ट भौतिकी सिमुलेशन प्रोग्रामिंग कर रहा हूँ। प्रदर्शन अच्छा है, लेकिन मैं इसे बेहतर बनाने के लिए अनुकूलन बनाने जा रहा हूं। इसलिए, क्योंकि कार्यक्रम बहुत भौतिक ज्यामिति के साथ काम करता है, मैं प्रोग्राम में कई पायथागोरियन प्रमेय गणना करता हूं। कुल मिलाकर, लगभग पांच गणना; एक साथ, वे प्रति सेकंड लगभग दस लाख बार चलाते हैं। इसलिए, मुझे लगा कि यह प्रदर्शन को बढ़ावा देगा अगर मैंने उस सरल पायथागोरियन प्रमेय कोड को एक नए समारोह में रखा और इसे बुलाया; आखिरकार, ब्राउजर के पास ऐसा करने के लिए कम संकलन है। तो, मैंने फ़ायरफ़ॉक्स में कोड चलाया और मिला .... 4000000% उस गणना के निष्पादन समय में बढ़ाएं।जेएस: फ़ंक्शन को कॉल करने में कितना समय लगता है?

कैसे? यह वही कोड है: Math.sqrt (x * x + y * y), तो फ़ंक्शन के रूप में इसे कैसे जोड़ना इसे धीमा कर देता है? मुझे लगता है कि कारण यह है कि कोड को निष्पादित किए बिना फ़ंक्शन को कॉल करने के लिए समय लगता है, और यह भी कि प्रति सेकंड इन देरी में से एक लाख इसे धीमा कर देता है?

यह मेरे लिए खतरनाक लगता है। क्या यह पूर्वनिर्धारित जेएस कार्यों पर भी लागू होगा? ऐसा असंभव लगता है, और यदि हां, तो वे इससे कैसे बचते हैं?

इस तरह जाने के लिए इस्तेमाल किया कोड:

function x() 
{ 
    dx=nx-mx; 
    dy=ny-my; 
    d=hypo(dx,dy); 
    doStuff(... 
} 
function hypo(x,y) 
{ 
    return Math.sqrt(x*x+y*y); 
} 

धन्यवाद:

function x() 
{ 
    dx=nx-mx; 
    dy=ny-my; 
    d=Math.sqrt(dx*dx+dy*dy); 
    doStuff(... 
} 

मैं क्या करने की कोशिश की इस था!

+3

क्या आपका फ़ंक्शन उस दायरे से बाहर परिभाषित किया गया है जो एक लाख बार एक सेकंड में चलाया जा रहा है? – alex

+0

और यह सच नहीं है कि ब्राउज़र में "करने के लिए कम संकलन" है क्योंकि आप इसे एक फ़ंक्शन में डालते हैं ... यह वास्तव में होना चाहिए, वास्तव में, क्योंकि संकलन एक स्टार्टअप चीज है। लेकिन @alex को शायद आपके 400% मंदी का कारण मिला :) – Ryan

+0

@alex हां, यह मुख्य विंडो में परिभाषित किया गया है। – mindoftea

उत्तर

7

फ़ंक्शन कॉल पूर्व-संकलित भाषाओं में नगण्य या यहां तक ​​कि अनुकूलन भी कर रहे हैं जो जेएस कभी नहीं रहा है। इसके अलावा, एक बड़ा सौदा ब्राउज़र पर निर्भर करता है।

वे व्याख्या की गई भाषाओं में सभी प्रदर्शनों की मौत हैं जो जेएस मुख्य रूप से काफी हाल ही में है। अधिकांश आधुनिक ब्राउज़रों में जेआईटी (जस्ट इन टाइम) कंपाइलर्स हैं जो अतीत के जेएस दुभाषियों से एक बड़ा अपग्रेड है, लेकिन मेरा मानना ​​है कि फ़ंक्शन कॉल किसी अन्य दायरे में अभी भी कुछ ओवरहेड खर्च करते हैं क्योंकि जेएस के कॉल ऑब्जेक्ट को यह निर्धारित करना होता है कि वास्तव में क्या कहा जा रहा है और इसका मतलब है विभिन्न स्कोप चेन ऊपर और नीचे मार्चिंग।

तो एक सामान्य नियम के रूप में: यदि आप IE8 के बारे में परवाह करते हैं और क्रोम और फ़ायरफ़ॉक्स के निचले और पुराने संस्करण फ़ंक्शन कॉल अवधि से बचते हैं। खासकर लूप के अंदर। जेआईटी ब्राउजर के लिए, मैं उम्मीद करता हूं कि अन्य फ़ंक्शन के अंदर परिभाषित एक फ़ंक्शन आम तौर पर फायदेमंद होगा (लेकिन मैं अभी भी परीक्षण करता हूं क्योंकि यह आईई 9 के लिए ब्रांड नई तकनीक है और सभी के लिए अपेक्षाकृत नया है)।

से एक और बात सावधान रहना। यदि कोई फ़ंक्शन विशेष रूप से जटिल होता है, तो जेआईटी उन्हें अनुकूलित करने के लिए कुछ भी नहीं कर सकता है।

https://groups.google.com/forum/#!msg/closure-compiler-discuss/4B4IcUJ4SUA/OqYWpSklTE4J

लेकिन समझने के लिए महत्वपूर्ण बात यह है कि जब कुछ बंद कर दिया जाता है और एक संदर्भ के अंदर ही कहा जाता है, एक समारोह के भीतर एक समारोह की तरह, यह आसान एक JIT का अनुकूलन करने के लिए होना चाहिए। किसी फ़ंक्शन के बाहर परिभाषित, यह निर्धारित करना है कि उस फ़ंक्शन की परिभाषा को बिल्कुल ठीक कहा जा रहा है। यह एक बाहरी समारोह में हो सकता है। यह वैश्विक हो सकता है। यह विंडो ऑब्जेक्ट के कन्स्ट्रक्टर के प्रोटोटाइप इत्यादि की एक संपत्ति हो सकती है ... ऐसी भाषा में जहां फ़ंक्शन प्रथम श्रेणी हैं, जिसका अर्थ है कि उनके संदर्भों को उसी तरह से पास किया जा सकता है जैसे आप डेटा पास करते हैं, आप वास्तव में उस चरण से बच नहीं सकते आपके वर्तमान संदर्भ के बाहर।

तो एक्स के अंदर हाइपो को परिभाषित करने का प्रयास करें कि क्या होता है।

व्याख्या की उम्र से सामान्य युक्तियों का एक और जोड़ी है कि अभी भी JITs में बहुमूल्य हो सकती है: '।'

  • someObject.property में ऑपरेटर, कैशिंग के लायक एक प्रक्रिया है। यह ओवरहेड खर्च करता है क्योंकि हर बार जब आप इसे इस्तेमाल करते हैं तो एक संबंधित कॉल ऑब्जेक्ट लुकअप प्रक्रिया होती है। मुझे लगता है कि क्रोम इस प्रक्रिया के परिणामों को संरक्षित नहीं करेगा क्योंकि पैरेंट ऑब्जेक्ट्स या प्रोटोटाइप में बदलाव वास्तव में किसी दिए गए संदर्भ के बाहर संदर्भित कर सकते हैं। आपके उदाहरण में यदि एक्स को लूप द्वारा उपयोग किया जा रहा है (संभवतया ठीक है या यहां तक ​​कि सहायक भी है यदि एक्स को एक ही कार्य में परिभाषित किया गया है जैसे कि जेआईटी में लूप - एक दुभाषिया में हत्या), तो मैं इसे इस्तेमाल करने से पहले एक var में Math.sqrt असाइन करने का प्रयास करूंगा हाइपो में अपने वर्तमान फ़ंक्शन के संदर्भ के बाहर सामानों के बहुत से संदर्भ होने से कुछ जेआईटी निर्णय ले सकते हैं कि यह अनुकूलित करने में परेशानी के लायक नहीं है लेकिन यह मेरे हिस्से पर शुद्ध अटकलें है।

//assume a giant array called someArray 
var i = someArray.length; //note the property lookup process being cached here 
//'someArray.reverse()' if original order isimportant 
while(i--){ 
    //now do stuff with someArray[i]; 
} 

टिप्पणी: कोड यहाँ किसी कारण से काम नहीं कर रहा ब्लॉक

  • निम्नलिखित शायद पाश सबसे तेज़ तरीका एक सरणी है।

    ऐसा करने से यह सहायक हो सकता है क्योंकि यह मूल रूप से कमी/कमी चरण और तार्किक तुलना को केवल कमी में बदल देता है, पूरी तरह से बाएं/दाएं तुलना ऑपरेटर की आवश्यकता को हटा देता है। ध्यान दें कि जेएस में दायीं ओर कमी ऑपरेटर का मतलब है कि मुझे मूल्यांकन के लिए पारित किया जाता है और फिर ब्लॉक के अंदर उपयोग किए जाने से पहले इसे कम किया जाता है। while(0) झूठे का मूल्यांकन करता है।

  • +0

    धन्यवाद; एक बहुत अच्छी व्याख्या! बड़े फ़ंक्शन के अंदर हाइपो फ़ंक्शन को परिभाषित करने में बहुत अधिक समय लगता है और मुझे इसे अन्य कार्यों में चाहिए, इसलिए यह मेरे लिए लायक नहीं है। जिज्ञासा से, हालांकि, मैंने इसे अंदर परिभाषित करने का प्रयास किया था। इसने 97% प्रदर्शन समस्याओं का हल किया! यह अभी भी फुलाया गया है, लेकिन बहुत बेहतर है। क्या आप जानते हैं कि पूर्वनिर्धारित कार्य इस से कैसे बचते हैं? एक बार फिर धन्यवाद! – mindoftea

    +0

    कोर जेएस ऑब्जेक्ट्स और विधियां वास्तव में बहुत कम स्तर पर चल रही हैं। यदि आप Math.sqrt को चेतावनी देने का प्रयास करते हैं, उदाहरण के लिए (कोई अभिभावक नहीं) तो आप शायद [नेटिव कोड] या अंदर के अंदर कुछ फ़ंक्शन देखेंगे। यह वास्तव में ब्राउज़र के पूर्व-संकलित रन-टाइम पर्यावरण से आम तौर पर एक कॉल खींच रहा है। यह अभी भी उन लुकअप को कैश करने में सहायक हो सकता है क्योंकि आप उन संदर्भों को मूल रूप से परिभाषित तरीकों से प्रतिस्थापित कर सकते हैं जो आप जेएस में चाहते हैं (बहुत स्मार्ट नहीं है लेकिन यह आपको ऐसा करने देता है)। जिसका मतलब है कि जेआईटी की लुकअप प्रक्रिया के लिए अभी भी खाता होना चाहिए। –

    +0

    इसके अलावा, अगर आपको अभी भी यह सब सेट अप हो गया है, तो Hypo परिभाषित इनलाइन को 'var sqrt = Math.sqrt' से पहले ठीक करें और उसके बाद हाइपो के अंदर sqrt को कॉल करें। मैं उत्सुक हूँ। –

    1

    मेरे आश्चर्य करने के लिए, के रूप में एरिक ने सुझाव दिया ज्यादा कुछ नहीं है अपने ब्राउज़र (क्रोमियम, लिनक्स) पर प्रदर्शन में सुधार करने, लेकिन लगता है देखने कैशिंग के बजाय प्रदर्शन दर्द होता है: http://jsperf.com/inline-metric-distance

    var optimizedDistance = (function() { 
        var sqrt = Math.sqrt; 
        return function (x, y) { return sqrt(x * x + y * y); } 
    })(); 
    

    धीमी है से

    var unoptimizedDistance = function(x, y) { 
        return Math.sqrt(x * x + y * y); 
    } 
    

    यहां तक ​​कि एक उपनाम बुला धीमी है

    var _sqrt = Math.sqrt; // _sqrt is slower than Math.sqrt! 
    

    लेकिन फिर, यह एक सटीक विज्ञान नहीं है और वास्तविक जीवन माप अभी भी भिन्न हो सकते हैं।

    फिर भी, मैं Math.sqrt का उपयोग करने के साथ जाऊंगा।

    +0

    दिलचस्प। मैं एक दूसरे में अपना खुद का परीक्षण करूंगा। – mindoftea

    +0

    ठीक है। मैंने मैथ कैशिंग के साथ और बिना सभी कोड का परीक्षण किया है। मैंने उन्हें ग्लोबल्स के रूप में परिभाषित किया ताकि मेरे विभिन्न कार्य उन्हें एक्सेस कर सकें और फिर इसे चला सकें। ऐसा लगता है कि कुछ मामलों में छोड़कर, कैशिंग किसी भी तरह धीमी थी। – mindoftea

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