स्ट्रिंग संयोजन सरणी जोड़ की तुलना में क्यों अधिक तेज होता है?


114

आज, मैंने इस धागे को स्ट्रिंग संघनन की गति के बारे में पढ़ा ।

हैरानी की बात यह है कि, स्ट्रिंग कॉनटेनमेंट विजेता था:

http://jsben.ch/#/OJ3vo

परिणाम मेरे विचार से विपरीत था। इसके अलावा, इस बारे में कई लेख हैं जो इस तरह के विरोध के बारे में बताते हैं ।

मैं अनुमान लगा सकता हूं कि ब्राउज़र concatनवीनतम संस्करण पर स्ट्रिंग के लिए अनुकूलित हैं , लेकिन वे ऐसा कैसे करते हैं? क्या हम यह कह सकते हैं कि +स्ट्रिंग को सुगम बनाने के लिए इसका उपयोग करना बेहतर है ?


अपडेट करें

इसलिए, आधुनिक ब्राउज़रों में स्ट्रिंग कॉन्फैनेटेशन को अनुकूलित किया गया है, ताकि जब आप स्ट्रैंथ को बदलना चाहते हैं, तो +संकेतों का उपयोग करने की तुलना में संकेतों का उपयोग करना तेज हो ।join

लेकिन @Aththur ने कहा कि joinयदि आप वास्तव में एक विभाजक के साथ तार जुड़ना चाहते हैं तो यह तेज है ।


अपडेट - २०२०
क्रोम: एरे joinलगभग 2 times fasterस्ट्रेंज कॉनैट है + देखें: https://stackoverflow.com/a/54970240-98/71

नोट के रूप में:

  • joinअगर आपके पास है तो ऐरे बेहतर हैlarge strings
  • यदि हमें several small stringsअंतिम आउटपुट में उत्पन्न होने की आवश्यकता है , तो स्ट्रिंग कॉनैट के साथ जाना बेहतर है +, क्योंकि अन्यथा ऐरे के साथ जाने पर अंत में स्ट्रिंग रूपांतरणों के लिए कई ऐरे की आवश्यकता होगी जो कि प्रदर्शन अधिभार है।


1
यह कोड 500 टेराबाइट कचरे का उत्पादन करने वाला है, लेकिन यह 200 एमएस में चलता है। मुझे लगता है कि वे सिर्फ एक स्ट्रिंग के लिए थोड़ा अधिक स्थान आवंटित करते हैं, और जब आप इसमें एक छोटी स्ट्रिंग जोड़ते हैं, तो यह आमतौर पर एक अतिरिक्त स्थान में फिट बैठता है।
इवान कुकिर

जवाबों:


149

ब्राउज़र स्ट्रिंग ऑप्टिमाइज़ेशन ने स्ट्रिंग कॉन्सेटन चित्र को बदल दिया है।

फ़ायरफ़ॉक्स स्ट्रिंग कॉन्सेप्टेशन को ऑप्टिमाइज़ करने वाला पहला ब्राउज़र था। संस्करण 1.0 से शुरू, सरणी तकनीक वास्तव में सभी मामलों में प्लस ऑपरेटर का उपयोग करने की तुलना में धीमी है। अन्य ब्राउज़रों ने भी स्ट्रिंग संयोजन को अनुकूलित किया है, इसलिए सफारी, ओपेरा, क्रोम, और इंटरनेट एक्सप्लोरर 8 भी प्लस ऑपरेटर का उपयोग करके बेहतर प्रदर्शन दिखाते हैं। संस्करण 8 से पहले इंटरनेट एक्सप्लोरर में ऐसा अनुकूलन नहीं था, और इसलिए सरणी तकनीक हमेशा प्लस ऑपरेटर की तुलना में तेज होती है।

- लेखन कुशल जावास्क्रिप्ट: अध्याय 7 - यहां तक ​​कि तेजी से वेबसाइटें

V8 जावास्क्रिप्ट इंजन (Google क्रोम में उपयोग किया जाता है) इस कोड का उपयोग स्ट्रिंग समवर्ती करने के लिए करता है:

// ECMA-262, section 15.5.4.6
function StringConcat() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
  }
  var len = %_ArgumentsLength();
  var this_as_string = TO_STRING_INLINE(this);
  if (len === 1) {
    return this_as_string + %_Arguments(0);
  }
  var parts = new InternalArray(len + 1);
  parts[0] = this_as_string;
  for (var i = 0; i < len; i++) {
    var part = %_Arguments(i);
    parts[i + 1] = TO_STRING_INLINE(part);
  }
  return %StringBuilderConcat(parts, len + 1, "");
}

इसलिए, आंतरिक रूप से वे इसे एक आंतरिकअरे ( partsचर) बनाकर अनुकूलित करते हैं , जो तब भर जाता है। StringBuilderConcat फ़ंक्शन को इन भागों के साथ कहा जाता है। यह तेज़ है क्योंकि StringBuilderConcat फ़ंक्शन कुछ भारी अनुकूलित C ++ कोड है। यहां उद्धृत करना बहुत लंबा है, लेकिन कोड देखने के लिए runtime.cc फ़ाइल में खोजें RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)


4
आपने वास्तव में दिलचस्प बात छोड़ दी, सरणी का उपयोग केवल Runtime_StringBuilderConcat को अलग-अलग तर्क गिनती के साथ करने के लिए किया जाता है। लेकिन असली काम तो वहीं होता है।
evilpie

41
अनुकूलन 101: आपको कम से कम धीमी गति के लिए लक्ष्य बनाना चाहिए! उदाहरण के लिए, arr.join vs str+क्रोम पर आपको (प्रति सेकंड संचालन में) मिलता है 25k/s vs 52k/s। फ़ायरफ़ॉक्स नया आपको मिलता है 76k/s vs 212k/s। इतना str+तेज है। लेकिन अन्य ब्राउज़रों को देखने देता है। ओपेरा 43k / s बनाम 26k / s देता है। IE देता है 1300/s vs 1002/s। देखते हैं क्या होता है? केवल ब्राउज़र है कि आवश्यकता अनुकूलन का उपयोग कर क्या सभी दूसरों, जहां यह बात बिल्कुल नहीं करता है पर धीमी है बंद बेहतर होगा। इसलिए, उन लेखों में से कोई भी प्रदर्शन के बारे में कुछ भी नहीं समझता है।
gcb

45
@gcb, एकमात्र ब्राउज़र जिसके लिए जुड़ना तेज़ है उसका उपयोग नहीं किया जाना चाहिए। मेरे 95% उपयोगकर्ताओं के पास FF और Chrome है। मैं 95% उपयोग के मामले में अनुकूलन करने जा रहा हूं।
पॉल ड्रेपर

7
@PaulDraper यदि 90% उपयोगकर्ता तेज़ ब्राउज़र पर हैं और आपके द्वारा चुने गए विकल्प में उन्हें 0.001 प्राप्त होंगे, लेकिन यदि आप अन्य उपयोगकर्ताओं को उस 0.001s से बाहर करने का निर्णय लेते हैं, तो आपके 10% उपयोगकर्ता 2 लाभ प्राप्त करेंगे ... निर्णय साफ है। यदि आप इसे नहीं देख सकते हैं, तो मुझे खेद है कि आप जिसके लिए भी कोड करेंगे।
gcb

7
पुराने ब्राउज़र अंततः चले जाएंगे, लेकिन उन सभी सरणी को जोड़ने के लिए किसी के वापस जाने की संभावना नहीं है। भविष्य के लिए कोड देना बेहतर है क्योंकि यह आपके वर्तमान उपयोगकर्ताओं के लिए एक बड़ी असुविधा नहीं है। पुराने ब्राउजर्स के साथ काम करने के दौरान ऑडियंस को कॉन्फिडेंस परफॉर्मेंस से ज्यादा चिंता की बात होती है।
थॉमस हिगिनबोटम

23

फ़ायरफ़ॉक्स तेज़ है क्योंकि यह रोप्स ( रोप्स: अ अल्टरनेटिव टू स्ट्रिंग्स ) नामक कुछ का उपयोग करता है । एक रस्सी मूल रूप से सिर्फ एक डीएजी है, जहां हर नोड एक स्ट्रिंग है।

उदाहरण के लिए, यदि आप ऐसा करेंगे a = 'abc'.concat('def'), तो नई बनाई गई वस्तु इस तरह दिखाई देगी। बेशक यह बिल्कुल ऐसा नहीं है कि यह स्मृति में कैसा दिखता है, क्योंकि आपको अभी भी स्ट्रिंग प्रकार, लंबाई और शायद अन्य के लिए एक फ़ील्ड की आवश्यकता है।

a = {
 nodeA: 'abc',
 nodeB: 'def'
}

तथा b = a.concat('123')

b = {
  nodeA: a, /* {
             nodeA: 'abc',
             nodeB: 'def'
          } */
  nodeB: '123'
}           

तो सरलतम मामले में VM को लगभग कोई काम नहीं करना है। एकमात्र समस्या यह है कि यह परिणामी स्ट्रिंग पर अन्य संचालन को थोड़ा धीमा कर देता है। इसके अलावा यह निश्चित रूप से स्मृति उपरि को कम करता है।

दूसरी ओर ['abc', 'def'].join('')आमतौर पर स्मृति में नए स्ट्रिंग फ्लैट को बिछाने के लिए केवल मेमोरी आवंटित करेंगे। (शायद यह अनुकूलित किया जाना चाहिए)


6

मुझे पता है कि यह एक पुराना धागा है, लेकिन आपका परीक्षण गलत है। आप ऐसा कर रहे हैं output += myarray[i];जबकि यह अधिक होना चाहिए output += "" + myarray[i];क्योंकि आप भूल गए हैं, कि आपको कुछ के साथ एक साथ आइटम गोंद करना है। संक्षिप्त कोड कुछ इस तरह होना चाहिए:

var output = myarray[0];
for (var i = 1, len = myarray.length; i<len; i++){
    output += "" + myarray[i];
}

इस तरह, आप एक साथ ग्लूइंग तत्वों के कारण एक के बजाय दो ऑपरेशन कर रहे हैं।

Array.join() ज्यादा तेज़ है।


मुझे आपका जवाब नहीं मिला। लगाने "" +और मूल के बीच अंतर क्या है ?
संग्युन ली

प्रत्येक पुनरावृत्ति पर एक के बजाय दो ऑपरेशन होते हैं जिसमें अधिक समय लगता है।
आर्थर

1
और हमें इसे लगाने की आवश्यकता क्यों है? हम पहले से ही outputइसके बिना आइटम को गोंद कर रहे हैं ।
संगुनुन ली

क्योंकि यह कैसे काम में शामिल है। उदाहरण के लिए, आप वह भी कर सकते हैं Array.join(",")जो आपके forपाश के साथ काम नहीं करेगा
आर्थर

ओहह मैं समझ गया। क्या आपने पहले से ही यह देखने के लिए परीक्षण किया है कि क्या शामिल है () तेज है?
संगुनुन ली

5

बड़ी मात्रा में डेटा जुड़ने का काम तेज है, इसलिए प्रश्न गलत बताया गया है।

let result = "";
let startTime = new Date().getTime();
for (let i = 0; i < 2000000; i++) {
    result += "x";
}
console.log("concatenation time: " + (new Date().getTime() - startTime));

startTime = new Date().getTime();
let array = new Array(2000000);
for (let i = 0; i < 2000000; i++) {
    array[i] = "x";
}
result = array.join("");
console.log("join time: " + (new Date().getTime() - startTime));

Chrome 72.0.3626.119, फ़ायरफ़ॉक्स 65.0.1, एज 42.17134.1.0 पर परीक्षण किया गया। ध्यान दें कि यह सरणी निर्माण के साथ भी तेज है!


~ अगस्त 2020. सत्य। Chrome में: Array Join time: 462. स्ट्रिंग कॉनैट (+) समय: 827. Join लगभग 2 गुना तेज है।
मनोहर रेड्डी पोरडे जूल

3

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

Array.join FTW!


2

मैं कहूंगा कि स्ट्रिंग्स के साथ एक बड़े बफर का प्रचार करना आसान है। प्रत्येक तत्व केवल 2 बाइट्स (यदि UNICODE) है, तो भले ही आप रूढ़िवादी हों, आप स्ट्रिंग के लिए एक बहुत बड़े बफर का प्रचार कर सकते हैं। arraysप्रत्येक तत्व के साथ अधिक "जटिल" है, क्योंकि प्रत्येक तत्व एक है Object, इसलिए एक रूढ़िवादी कार्यान्वयन कम तत्वों के लिए स्थान का प्रचार करेगा।

यदि आप for(j=0;j<1000;j++)प्रत्येक से पहले जोड़ने की कोशिश करते हैं forतो आप देखेंगे कि (क्रोम के नीचे) गति में अंतर छोटा हो जाता है। अंत में यह स्ट्रिंग के संघनन के लिए अभी भी 1.5x था, लेकिन पहले के 2.6 से छोटा था।

और तत्वों की नकल करने के लिए, एक यूनिकोड वर्ण संभवतः जेएस ऑब्जेक्ट के संदर्भ से छोटा है।

विदित हो कि जेएस इंजन के कई कार्यान्वयनों में एकल-प्रकार के सरणियों के लिए एक अनुकूलन है, जो मेरे द्वारा उपयोग किए जाने वाले सभी :-)


1

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


0

यह स्पष्ट रूप से जावास्क्रिप्ट इंजन कार्यान्वयन पर निर्भर करता है। यहां तक ​​कि एक इंजन के विभिन्न संस्करणों के लिए आप अलग-अलग परिणाम प्राप्त कर सकते हैं। इसे सत्यापित करने के लिए आपको अपना स्वयं का मानदंड करना चाहिए।

मैं कहूंगा कि String.concatV8 के हाल के संस्करणों में बेहतर प्रदर्शन किया है। लेकिन फ़ायरफ़ॉक्स और ओपेरा के लिए, Array.joinएक विजेता है।


-1

मेरा अनुमान है कि, जबकि हर संस्करण में कई संघों की लागत होती है, इसके अतिरिक्त शामिल होने वाले संस्करण सरणियों का निर्माण कर रहे हैं।

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