बाद का कार्य 10% तेजी से क्यों होता है, हालांकि इसे चर को बार-बार बनाना चाहिए?


14
var toSizeString = (function() {

 var KB = 1024.0,
     MB = 1024 * KB,
     GB = 1024 * MB;

  return function(size) {
    var gbSize = size / GB,
        gbMod  = size % GB,
        mbSize = gbMod / MB,
        mbMod  = gbMod % MB,
        kbSize = mbMod / KB;

    if (Math.floor(gbSize)) {
      return gbSize.toFixed(1) + 'GB';
    } else if (Math.floor(mbSize)) {
      return mbSize.toFixed(1) + 'MB';
    } else if (Math.floor(kbSize)) {
      return kbSize.toFixed(1) + 'KB';
    } else {
      return size + 'B';
    }
  };
})();

और तेज़ कार्य: (ध्यान दें कि यह हमेशा एक ही चर kb / mb / gb को बार-बार गणना करना चाहिए)। यह प्रदर्शन कहाँ प्राप्त करता है?

function toSizeString (size) {

 var KB = 1024.0,
     MB = 1024 * KB,
     GB = 1024 * MB;

 var gbSize = size / GB,
     gbMod  = size % GB,
     mbSize = gbMod / MB,
     mbMod  = gbMod % MB,
     kbSize = mbMod / KB;

 if (Math.floor(gbSize)) {
      return gbSize.toFixed(1) + 'GB';
 } else if (Math.floor(mbSize)) {
      return mbSize.toFixed(1) + 'MB';
 } else if (Math.floor(kbSize)) {
      return kbSize.toFixed(1) + 'KB';
 } else {
      return size + 'B';
 }
};

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

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

आप निरंतर मूल्यों के संदर्भ में "गणना" शब्द का उपयोग करते हैं; वहाँ वास्तव में करने के लिए कुछ भी नहीं है की गणना आप क्या संदर्भित कर रहे हैं वहाँ। निरंतर मूल्यों का अंकगणित सबसे सरल और स्पष्ट अनुकूलन संकलक में से एक है, इसलिए कभी भी आप एक अभिव्यक्ति देखते हैं जिसमें केवल निरंतर मान होते हैं, आप बस मान सकते हैं कि पूरी अभिव्यक्ति एक एकल निरंतर मान के अनुकूल है।
जिमी हॉफ

@JimmyHoffa यह सच है, लेकिन दूसरी ओर इसे 3 फंक्शन्स बनाने की जरूरत है, हर फंक्शन कॉल ...
Tomy

@ निरंतर स्थिरांक चर नहीं हैं। वे भिन्न नहीं होते हैं, इस प्रकार उन्हें संकलन के बाद फिर से बनाने की आवश्यकता नहीं है। एक स्थिरांक को आम तौर पर स्मृति में रखा जाता है, और उस स्थिरांक के लिए हर भविष्य की पहुंच को उसी स्थान पर निर्देशित किया जाता है, इसे फिर से बनाने की कोई आवश्यकता नहीं है क्योंकि यह मान कभी अलग नहीं होगा , इसलिए यह एक चर नहीं है। कंपाइलर आमतौर पर ऐसे कोड का उत्सर्जन नहीं करेगा जो लगातार बनाता है, कंपाइलर निर्माण करता है और यह सभी कोड संदर्भों को निर्देश देता है कि यह क्या बनाया है।
जिमी हॉफ

जवाबों:


23

आधुनिक जावास्क्रिप्ट इंजन सभी समय-समय पर संकलन करते हैं। आप इसके बारे में कोई अनुमान नहीं लगा सकते हैं कि "इसे बार-बार बनाना चाहिए।" इस प्रकार की गणना किसी भी स्थिति में, इसे अनुकूलित करना अपेक्षाकृत आसान है।

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

इस तरह की स्थिति यह है कि लोग "समय से पहले अनुकूलन" लाइन क्यों फेंकते हैं। आसान अनुकूलन पहले से ही संकलक द्वारा किया जाता है।


मुझे संदेह है कि यह चर रिज़ॉल्यूशन के लिए वैरिएबल रिज़ॉल्यूशन है जो आपके उल्लेख के अनुसार नुकसान का कारण है। उचित लगता है, लेकिन जो वास्तव में जानता है कि एक जावास्क्रिप्ट JIT इंजन में क्या पागलपन है ...
जिमी होफा

1
इस उत्तर का संभावित विस्तार: जेआईटी एक ऑफ़लाइन कंपाइलर के लिए आसान ऑप्टिमाइज़ेशन को अनदेखा करने का कारण होगा क्योंकि पूरे कंपाइलर का प्रदर्शन असामान्य मामलों की तुलना में अधिक महत्वपूर्ण है।
लेउशेंको

12

चर सस्ते होते हैं। निष्पादन संदर्भ और गुंजाइश श्रृंखलाएं महंगी हैं।

विभिन्न उत्तर हैं जो अनिवार्य रूप से "क्योंकि क्लोजर" को उबालते हैं, और वे अनिवार्य रूप से सच हैं, लेकिन समस्या विशेष रूप से बंद होने के साथ नहीं है , यह तथ्य है कि आपके पास एक फ़ंक्शन है जो भिन्न दायरे में चर का संदर्भ देता है। यदि आप windowऑब्जेक्ट पर वैश्विक चर थे, तो यही समस्या होगी , क्योंकि IIFE के अंदर स्थानीय चर के विपरीत। यह कोशिश करो और देखो।

तो अपने पहले फ़ंक्शन में, जब इंजन इस कथन को देखता है:

var gbSize = size / GB;

इसके लिए निम्न कदम उठाने होंगे:

  1. sizeवर्तमान क्षेत्र में एक चर के लिए खोजें । (मिल गया।)
  2. GBवर्तमान क्षेत्र में एक चर के लिए खोजें । (नहीं मिला।)
  3. GBपैरेंट स्कोप में वैरिएबल की खोज करें । (मिल गया।)
  4. गणना करें और करने के लिए असाइन करें gbSize

चरण 3 एक चर आवंटित करने की तुलना में काफी अधिक महंगा है। इसके अलावा, आप इसे पांच बार करते हैं , दोनों के लिए दो बार GBऔर MB। मुझे संदेह है कि यदि आपने फ़ंक्शन की शुरुआत में इन्हें var gb = GBअलियास किया (उदाहरण के लिए ) और इसके बजाय उर्फ ​​को संदर्भित किया, तो यह वास्तव में एक छोटे स्पीडअप का उत्पादन करेगा, हालांकि यह भी संभव है कि कुछ जेएस इंजन पहले से ही इस अनुकूलन का प्रदर्शन करें। और निश्चित रूप से, निष्पादन को गति देने का सबसे प्रभावी तरीका बस गुंजाइश श्रृंखला को पार करना नहीं है।

ध्यान रखें कि जावास्क्रिप्ट संकलित, वैधानिक रूप से टाइप की गई भाषा की तरह नहीं है, जहां संकलनकर्ता संकलन समय पर इन चर पते को हल करता है। JS इंजन को उन्हें नाम से हल करना होगा, और ये लुकअप हर बार, रनटाइम पर होते हैं। इसलिए जब संभव हो आप उनसे बचना चाहते हैं।

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


और यहां तक ​​कि अगर "अनुकूलन" प्रदर्शन को नकारात्मक रूप से प्रभावित नहीं करता है, तो यह लगभग निश्चित रूप से कोड पठनीयता को नकारात्मक रूप से प्रभावित करने वाला है। जो, जब तक आप कुछ पागल कम्प्यूटेशनल सामान नहीं कर रहे हैं, तब तक बनाने के लिए सबसे अधिक बार खराब ट्रेडऑफ होता है (दुर्भाग्य से कोई permalinkor दुर्भाग्य से; "2009-02-17 11:41" के लिए खोज करें)। जैसा कि सारांश है: "गति पर स्पष्टता चुनें, अगर गति की बिल्कुल जरूरत नहीं है।"
एक CVn

गतिशील भाषाओं के लिए एक बहुत ही बुनियादी व्याख्याकार लिखते समय, रनटाइम के दौरान चर पहुंच एक ओ (1) ऑपरेशन हो जाता है, और प्रारंभिक संकलन के दौरान ओ (एन) स्कोपर्स ट्रैवेलर की भी आवश्यकता नहीं होती है। प्रत्येक दायरे में, प्रत्येक नव घोषित चर को एक नंबर दिया जाता है, ताकि दिए गए var a, b, cहम उपयोग कर सकते हैं bके रूप में scope[1]। सभी स्कोपों ​​को क्रमांकित किया गया है, और यदि इस दायरे को पांच स्कोपों ​​से गहरा घोंसला बनाया गया है, तो bपूरी तरह से संबोधित किया env[5][1]जाता है, जिसे पार्सिंग के दौरान जाना जाता है। मूल कोड में, स्कोप्स स्टैक सेगमेंट के अनुरूप हैं। क्लोज़र अधिक जटिल हैं क्योंकि उन्हें env
एमोन

@amon: यह कैसे आप चाहते आदर्श हो सकता है की तरह यह काम करने के लिए, लेकिन ऐसा नहीं है कि यह वास्तव में कैसे काम करता है। जितना मैंने इस बारे में किताबें लिखी हैं, उससे कहीं अधिक जानकार और अनुभवी लोग; विशेष रूप से मैं आपको निकोलस सी। ज़कस द्वारा उच्च प्रदर्शन जावास्क्रिप्ट की ओर इशारा करता हूँ। यहाँ एक स्निपेट है , और उन्होंने इसे वापस करने के लिए बेंचमार्क के साथ एक बात भी की। बेशक वह निश्चित रूप से एकमात्र नहीं है, बस सबसे प्रसिद्ध है। जावास्क्रिप्ट में शाब्दिक स्कूपिंग है, इसलिए वास्तव में क्लोजर वास्तव में उस विशेष नहीं हैं - अनिवार्य रूप से, सब कुछ एक क्लोजर है।
एरोनियट

@Aaronaught दिलचस्प। चूँकि वह पुस्तक 5 साल पुरानी है, मुझे दिलचस्पी थी कि कैसे एक वर्तमान जेएस इंजन वैरिएबल लुकअप को संभालता है और वी 8 इंजन के x64 बैकएंड को देखता है। स्थैतिक विश्लेषण के दौरान, अधिकांश चर को सांख्यिकीय रूप से हल किया जाता है और उन्हें अपने दायरे में एक मेमोरी ऑफसेट सौंपा जाता है। फ़ंक्शन स्कोप्स को लिंक की गई सूचियों के रूप में दर्शाया जाता है, और विधानसभा को सही दायरे तक पहुंचने के लिए एक अनियंत्रित लूप के रूप में उत्सर्जित किया जाता है। यहां, हमें *(scope->outer + variable_offset)एक्सेस के लिए C कोड के बराबर मिलेगा ; प्रत्येक अतिरिक्त फ़ंक्शन स्कोप के स्तर पर एक अतिरिक्त पॉइंटर डेरेफेरेंस का खर्च आता है। लगता है हम दोनों सही थे :)
amon

2

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

एक क्लोजर में केवल एक फंक्शन ही नहीं होता है, बल्कि सभी वैरिएबल भी बंद होते हैं। जब हम उस फ़ंक्शन को लागू करना चाहते हैं, तो हमें सभी बंद किए गए चर भी प्रदान करने होंगे। हम एक फ़ंक्शन द्वारा एक क्लोजर को मॉडल कर सकते हैं जो ऑब्जेक्ट को पहले तर्क के रूप में प्राप्त करता है जो इन बंद चर पर प्रतिनिधित्व करता है:

function add(vars, y) {
  vars.x += y;
}

function getSum(vars) {
  return vars.x;
}

function makeAdder(x) {
  return { x: x, add: add, getSum: getSum };
}

var adder = makeAdder(40);
adder.add(adder, 2);
console.log(adder.getSum(adder));  //=> 42

नोट अजीब बुला सम्मेलन closure.apply(closure, ...realArgs)इस की आवश्यकता है

जावास्क्रिप्ट का अंतर्निहित वस्तु समर्थन स्पष्ट varsतर्क को छोड़ना संभव बनाता है , और thisइसके बजाय हमें उपयोग करने देता है :

function add(y) {
  this.x += y;
}

function getSum() {
  return this.x;
}

function makeAdder(x) {
  return { x: x, add: add, getSum: getSum };
}

var adder = makeAdder(40);
adder.add(2);
console.log(adder.getSum());  //=> 42

वे उदाहरण वास्तव में क्लोजर का उपयोग करते हुए इस कोड के बराबर हैं:

function makeAdder(x) {
  return {
    add: function (y) { x += y },
    getSum: function () { return x },
  };
}

var adder = makeAdder(40);
adder.add(2);
console.log(adder.getSum());  //=> 42

इस अंतिम उदाहरण में, ऑब्जेक्ट का उपयोग केवल दो लौटे फ़ंक्शन को समूहित करने के लिए किया जाता है; thisबंधन अप्रासंगिक है। क्लोजर को संभव बनाने के सभी विवरण - छिपे हुए डेटा को वास्तविक फ़ंक्शन में पास करना, सभी एक्सेस को बंद करने के चर को उस छिपे हुए डेटा में लुकअप में बदलना - भाषा द्वारा ध्यान रखा जाता है।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.