javascript v8 जावास्क्रिप्ट कॉन्स्टैक्शन का निहितार्थ, आइए, और var है?




performance const (4)

टी एल; डॉ

सिद्धांत रूप में , इस लूप का एक अपनाने वाला संस्करण:

for (let i = 0; i < 500; ++i) {
    doSomethingWith(i);
}

वैरिएबल के साथ एक ही लूप के अनअप्टिमाइज्ड वर्जन से धीमी होगी:

for (var i = 0; i < 500; ++i) {
    doSomethingWith(i);
}

चूँकि प्रत्येक लूप पुनरावृत्ति के लिए एक अलग i वैरिएबल बनाया गया है, जबकि var साथ केवल एक i

व्यवहार में , 2018 में, V8 यह जानने के लिए लूप का पर्याप्त आत्मनिरीक्षण करता है कि यह उस अंतर को कब दूर कर सकता है। (इससे पहले भी, ऑड्स हैं आपका लूप पर्याप्त काम कर रहा था कि अतिरिक्त ले-रिलेटेड ओवरहेड को वैसे भी धोया गया था। लेकिन अब आपको इसके बारे में चिंता करने की ज़रूरत नहीं है।)

विवरण

एक लूप में var और let बीच महत्वपूर्ण अंतर यह है कि प्रत्येक पुनरावृत्ति के लिए एक अलग i बनाया जाता है; यह क्लासिक "पाश में बंद" समस्या को संबोधित करता है:

function usingVar() {
  for (var i = 0; i < 3; ++i) {
    setTimeout(function() {
      console.log("var's i: " + i);
    }, 0);
  }
}
function usingLet() {
  for (let i = 0; i < 3; ++i) {
    setTimeout(function() {
      console.log("let's i: " + i);
    }, 0);
  }
}
usingVar();
setTimeout(usingLet, 20);

प्रत्येक लूप बॉडी ( विशेष लिंक ) के लिए नया एन्वायरमेंटलकार्ड बनाना काम है, और काम में समय लगता है, यही वजह है कि सिद्धांत रूप में let वर्जन वर्जन की तुलना में धीमा है।

लेकिन अंतर केवल तब होता है जब आप लूप के भीतर एक फंक्शन (क्लोजर) बनाते हैं जो i का उपयोग करता है, जैसा कि मैंने उस रननेबल स्निपेट उदाहरण में किया था। अन्यथा, भेद नहीं देखा जा सकता है और इसे दूर अनुकूलित किया जा सकता है।

यहाँ 2018 में, ऐसा लगता है कि V8 (और फ़ायरफ़ॉक्स में स्पाइडरमॉन्की) पर्याप्त आत्मनिरीक्षण कर रहा है कि लूप में कोई प्रदर्शन लागत नहीं है जो let -वेरिएबल-प्रति-इट्रेशन शब्दार्थ का उपयोग नहीं करता है। इस jsPerf परीक्षण को देखें।

कुछ मामलों में, const अच्छी तरह से अनुकूलन के लिए एक अवसर प्रदान कर सकता है जो विशेष रूप से वैश्विक चर के लिए नहीं होगा।

वैश्विक चर के साथ समस्या यह है कि यह अच्छी तरह से, वैश्विक है; कहीं भी कोई भी कोड इसे एक्सेस कर सकता है। इसलिए यदि आप ऐसे वेरिएबल को var साथ घोषित करते हैं जिसे आप कभी बदलने का इरादा नहीं करते हैं (और अपने कोड में कभी भी बदलाव नहीं करते हैं), इंजन यह नहीं मान सकता है कि यह कोड के परिणाम के रूप में बाद में या इसी तरह लोड होने वाला है।

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

Objects याद रखें कि वस्तुओं के साथ, मूल्य वस्तु का संदर्भ है, वस्तु का नहीं। तो const o = {} , आप ऑब्जेक्ट की स्थिति ( o.answer = 42 ) को बदल सकते हैं, लेकिन आप किसी नई ऑब्जेक्ट के लिए o पॉइंट नहीं बना सकते हैं (क्योंकि इसमें ऑब्जेक्ट का संदर्भ बदलने की आवश्यकता होगी)।

अन्य प्रकार की स्थितियों में let या const का उपयोग let , उनके अलग-अलग प्रदर्शन होने की संभावना नहीं होती है। इस फ़ंक्शन का ठीक वैसा ही प्रदर्शन होना चाहिए, जैसे आप var या let उपयोग let , उदाहरण के लिए:

function foo() {
    var i = 0;
    while (Math.random() < 0.5) {
        ++i;
    }
    return i;
}

यह सब, ज़ाहिर है, कोई फर्क नहीं पड़ता है और कुछ के बारे में चिंता करने के लिए केवल अगर और जब कोई वास्तविक समस्या हल करने के लिए है।

https://code.i-harness.com

कार्यात्मक अंतरों के बावजूद, नए कीवर्ड 'लेट' और 'कॉन्स्ट' का उपयोग करने से 'संस्करण' के सापेक्ष प्रदर्शन पर कोई सामान्य या विशिष्ट प्रभाव पड़ता है?

कार्यक्रम चलाने के बाद:

function timeit(f, N, S) {
    var start, timeTaken;
    var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
    var i;
    for (i = 0; i < S; ++i) {
        start = Date.now();
        f(N);
        timeTaken = Date.now() - start;

        stats.min = Math.min(timeTaken, stats.min);
        stats.max = Math.max(timeTaken, stats.max);
        stats.sum += timeTaken;
        stats.sqsum += timeTaken * timeTaken;
        stats.N++
    }

    var mean = stats.sum / stats.N;
    var sqmean = stats.sqsum / stats.N;

    return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}

var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;

function varAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += variable1;
        sum += variable2;
        sum += variable3;
        sum += variable4;
        sum += variable5;
        sum += variable6;
        sum += variable7;
        sum += variable8;
        sum += variable9;
        sum += variable10;
    }
    return sum;
}

const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;

function constAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += constant1;
        sum += constant2;
        sum += constant3;
        sum += constant4;
        sum += constant5;
        sum += constant6;
        sum += constant7;
        sum += constant8;
        sum += constant9;
        sum += constant10;
    }
    return sum;
}


function control(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
    }
    return sum;
}

console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));

.. मेरे परिणाम निम्नलिखित थे:

ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}

हालाँकि, जैसा कि यहाँ उल्लेख किया गया है, कुछ परिदृश्यों के तहत प्रदर्शन के अंतर की वास्तविक क्षमता का संकेत देता है: https://esdiscuss.org/topic/performance-concern-with-let-const


टीजे क्राउडर का जवाब बहुत अच्छा है लेकिन:

  1. 'लेट' कोड को अधिक पठनीय बनाने के लिए किया जाता है, अधिक शक्तिशाली नहीं
  2. सिद्धांत रूप में चलो var की तुलना में धीमी हो जाएगी
  3. अभ्यास से संकलक पूरी तरह से (स्थैतिक विश्लेषण) एक अपूर्ण कार्यक्रम को हल नहीं कर सकता है इसलिए कुछ समय में यह अनुकूलन को याद करेगा
  4. किसी भी स्थिति में 'लेट' का उपयोग करते हुए आत्मनिरीक्षण के लिए अधिक सीपीयू की आवश्यकता होगी, जब Google v8 को पार्स करना शुरू होता है तो बेंच को शुरू किया जाना चाहिए
  5. यदि आत्मनिरीक्षण विफल हो जाता है 'चलो' V8 कचरा संग्राहक पर जोर देगा, तो इसे खाली / पुन: उपयोग करने के लिए अधिक पुनरावृत्ति की आवश्यकता होगी। यह अधिक रैम की खपत करेगा। पीठ को इन बिंदुओं को ध्यान में रखना चाहिए
  6. गूगल क्लोजर को बदल देगा var ...

वर्जन और लेट के बीच परफॉरमेंस गैप का असर रियल-लाइफ कम्प्लीट प्रोग्राम में देखा जा सकता है न कि एक बेसिक लूप पर।

वैसे भी, यह बताने के लिए कि आपको कहां नहीं करना है, आपके कोड को कम पठनीय बनाता है।


"LET" LOOP घोषणाओं में बेहतर है

एक साधारण परीक्षण (5 बार) जैसे नाविक में:

// WITH VAR
console.time("var-time")
for(var i = 0; i < 500000; i++){}
console.timeEnd("var-time")

निष्पादित करने का औसत समय 2.5ms से अधिक है

// WITH LET
console.time("let-time")
for(let i = 0; i < 500000; i++){}
console.timeEnd("let-time")

निष्पादित करने का औसत समय 1.5ms से अधिक है

मैंने पाया कि लूप का समय बेहतर है।


टीजे क्राउडर का जवाब बहुत अच्छा है।

यहाँ एक अतिरिक्त दिया गया है: "जब मुझे कब्ज़े के लिए मौजूदा var घोषणाओं को संपादित करने पर मेरे हिरन के लिए सबसे अधिक धमाका होगा?"

मैंने पाया है कि सबसे अधिक प्रदर्शन को बढ़ावा "निर्यात" कार्यों के साथ करना था।

इसलिए यदि फाइल A, B, R, और Z फाइल यू में "यूटिलिटी" फंक्शन पर कॉल कर रहे हैं जो आमतौर पर आपके ऐप के माध्यम से उपयोग किया जाता है, तो उस यूटिलिटी फंक्शन को "कॉन्स्ट" पर स्विच करना और पेरेंट फाइल रेफरेंस को एक eak कर सकते हैं। कुछ बेहतर प्रदर्शन किया। यह मेरे लिए लग रहा था कि यह औसत रूप से तेज नहीं था, लेकिन मेरे सकल अखंडित फ्रेंकस्टीन-एड ऐप के लिए समग्र मेमोरी खपत लगभग 1-3% कम हो गई थी। यदि आप क्लाउड या अपने नंगे सर्वर पर नकदी के बैग खर्च कर रहे हैं, तो कंघी करने के लिए 30 मिनट खर्च करने और उन वार्ताओं की कुछ घोषणाओं को अपडेट करने का एक अच्छा कारण हो सकता है।

मुझे लगता है कि यदि आप पढ़ते हैं कि कैसे कॉन्स्ट, वर्, और कवर के तहत काम करते हैं तो आप शायद पहले ही ऊपर निष्कर्ष निकाल चुके हैं ... लेकिन यदि आप इस पर "नज़र" रखते हैं: डी।

जब मैं अद्यतन कर रहा था, तो नोड v8.12.0 पर बेंचमार्किंग से मुझे जो याद आया, उससे मेरा ऐप ~ 240MB RAM ~ 233MB RAM की बेकार खपत से चला गया।





let