2011-09-04 20 views
95

आज, मैंने स्ट्रिंग कॉन्सटेनेशन की गति के बारे में this thread पढ़ा।स्ट्रिंग concatenation सरणी से अधिक तेजी से क्यों शामिल है?

http://jsben.ch/#/OJ3vo

परिणाम मैं क्या सोचा से विपरीत था:

हैरानी की बात है, स्ट्रिंग संयोजन विजेता था। इसके अलावा, इसके बारे में कई लेख हैं जो this या this जैसे विपरीत बताते हैं।

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

+1

[यह कोड] (https://jsfiddle.net/8jyer0tp/) कचरे के 500 टेराबाइट्स निर्माण करने के लिए माना जाता है, लेकिन यह 200 एमएस में चलता है। मुझे लगता है कि वे सिर्फ एक स्ट्रिंग के लिए थोड़ा अधिक स्थान आवंटित करते हैं, और जब आप इसे एक छोटी स्ट्रिंग जोड़ते हैं, तो यह आमतौर पर एक अतिरिक्त स्थान में फिट बैठता है। –

उत्तर

131

ब्राउज़र स्ट्रिंग अनुकूलन स्ट्रिंग संयोजन बदल गया है है कि हो सकता है चित्र।

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

- Writing Efficient JavaScript: Chapter 7 – Even Faster Websites

V8 javascript इंजन (गूगल क्रोम में प्रयुक्त) this code का उपयोग करता स्ट्रिंग संयोजन करना है:

// 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, ""); 
} 

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

+3

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

+1

इसे उत्तर में जोड़ा गया, सिर के लिए धन्यवाद! – Daan

+1

_ यह तेज़ है क्योंकि [यह] भारी अनुकूलित_ लेकिन किस तरह से? यह सवाल है। – artistoex

-1

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

2

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

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

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

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

19

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

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

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

और b = a.concat('123')

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

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

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

0

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

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

1

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

3

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

Array.join FTW!

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