2008-08-09 15 views
144

मान लीजिए मैं सी # में एक stringbuilder है कि इस करता है:StringBuilder के रूप में कुशल के रूप में String.Format है

StringBuilder sb = new StringBuilder(); 
string cat = "cat"; 
sb.Append("the ").Append(cat).(" in the hat"); 
string s = sb.ToString(); 

कि के रूप में कुशल या होने के रूप में किसी भी अधिक कुशल हो जाएगा:

string cat = "cat"; 
string s = String.Format("The {0} in the hat", cat); 

यदि हां , क्यूं कर?

संपादित

कुछ दिलचस्प जवाब के बाद मैंने महसूस मैं शायद मैं क्या पूछ रहा था में एक छोटे से साफ किया जाना चाहिए था। मैं इतनी ज्यादा नहीं पूछ रहा था कि एक स्ट्रिंग को संयोजित करने में तेज़ था, लेकिन इंजेक्शन को एक स्ट्रिंग में तेज कर रहा था।

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

क्षमा

+0

भविष्य में सुधार की अनुमति देने के लिए कृपया इन्हें खोलें। –

+3

एक विशेष मामले परिदृश्य में, इनमें से सबसे तेज़ नहीं है: यदि भाग को प्रतिस्थापित किया जाए तो आकार के बराबर बराबर है, तो आप स्ट्रिंग को जगह में बदल सकते हैं। दुर्भाग्य से, इसके लिए प्रतिबिंब या असुरक्षित कोड की आवश्यकता होती है और जानबूझकर स्ट्रिंग की अपरिवर्तनीयता का उल्लंघन करती है। एक अच्छा अभ्यास नहीं है, लेकिन यदि गति एक मुद्दा है ... :) – Abel

+0

ऊपर दिए गए उदाहरण में '' 'स्ट्रिंग एस =" टोपी में "+ बिल्ली +" ";' '' '' 'का उपयोग तब तक किया जा सकता है जब तक इसका उपयोग नहीं किया जाता एक लूप में, जिस मामले में सबसे तेज़ लूप के बाहर ''' स्ट्रिंगबिल्डर' '' के साथ शुरू होगा। –

उत्तर

136

String.Format का उपयोग करता है एक StringBuilder आंतरिक:

public static string Format(IFormatProvider provider, string format, params object[] args) 
{ 
    if ((format == null) || (args == null)) 
    { 
     throw new ArgumentNullException((format == null) ? "format" : "args"); 
    } 

    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8)); 
    builder.AppendFormat(provider, format, args); 
    return builder.ToString(); 
} 

ऊपर कोड mscorlib से एक टुकड़ा है, इसलिए सवाल "StringBuilder.Append()StringBuilder.AppendFormat() की तुलना में तेजी है," हो जाता है?

बेंचमार्किंग के बिना मैं शायद कहूंगा कि उपरोक्त कोड नमूना .Append() का उपयोग करके अधिक तेज़ी से चलाएगा। लेकिन यह एक अनुमान है, उचित तुलना करने के लिए दोनों को बेंचमार्किंग और/या प्रोफाइलिंग करने का प्रयास करें।

http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

अपडेट किया गया::

दुर्भाग्य से ऊपर दी गई लिंक के बाद से मर गया

यह अध्याय, जैरी डिक्सन, कुछ बेंच मार्किंग किया था। लेकिन वहाँ अभी भी वे बैक मशीन पर एक कॉपी:

http://web.archive.org/web/20090417100252/http://jdixon.dotnetdevelopersjournal.com/string_concatenation_stringbuilder_and_stringformat.htm

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

+6

जेरी डिक्सन के पेज पर बेंचमार्क के साथ एक समस्या यह है कि वह 'StringBuilder' ऑब्जेक्ट पर '.ToString()' को कभी भी कॉल नहीं करता है। बहुत सारे पुनरावृत्तियों में, उस समय एक बड़ा अंतर आता है, और इसका मतलब है कि वह सेब से सेब की तुलना नहीं कर रहा है। यही कारण है कि वह 'स्ट्रिंगबिल्डर' के लिए इस तरह के महान प्रदर्शन दिखाता है और शायद उसके आश्चर्य के लिए जिम्मेदार है। मैंने उस गलती को ठीक करने वाले बेंचमार्क को दोहराया और अपेक्षित परिणाम प्राप्त किए: 'स्ट्रिंग '' ऑपरेटर' स्ट्रिंगबिल्डर 'के बाद,' स्ट्रिंग.फॉर्मैट 'के साथ पीछे की ओर ला रहा था। –

+5

6 साल बाद, यह अब और अधिक नहीं है। नेट 4 में, string.Format() स्ट्रिंगबिल्डर उदाहरण बनाता है और इसे कैश करता है, जिससे यह कुछ परीक्षण मामलों में स्ट्रिंगबिल्डर से तेज हो सकता है। मैंने नीचे दिए गए उत्तर में एक संशोधित बेंचमार्क लगाया है (जो अभी भी कहता है कि कॉन्सैट सबसे तेज़ है और मेरे टेस्ट केस के लिए, प्रारूप स्ट्रिंगबिल्डर से 10% धीमा है)। –

-2

मैं, नहीं सुझाव है के बाद से String.Format संयोजन के लिए नहीं बनाया गया था, यह इस तरह के एक तारीख के रूप में विभिन्न आदानों की उत्पादन फ़ॉर्मेट करने के लिए डिजाइन किया गया था।

String s = String.Format("Today is {0:dd-MMM-yyyy}.", DateTime.Today); 
0

यह वास्तव में निर्भर करता है। कुछ concatenations के साथ छोटे तारों के लिए, यह तारों को जोड़ने के लिए वास्तव में तेजी से है।

String s = "String A" + "String B"; 

लेकिन बड़ी स्ट्रिंग (बहुत बहुत बड़ी तार) के लिए, यह स्ट्रिंगबिल्डर का उपयोग करने के लिए और अधिक कुशल है।

43
MSDN documentation से

:

एक स्ट्रिंग या StringBuilder वस्तु के लिए एक संयोजन आपरेशन के प्रदर्शन कितनी बार एक स्मृति आवंटन होता है पर निर्भर करता है। एक स्ट्रिंग कॉन्सटेनेशन ऑपरेशन हमेशा स्मृति आवंटित करता है, जबकि स्ट्रिंगबिल्डर ऑब्जेक्ट बफर केवल नए आवंटित करने के लिए स्ट्रिंगबिल्डर ऑब्जेक्ट बफर बहुत छोटा होता है, तो स्मृति को आवंटित करता है। नतीजतन, यदि स्ट्रिंग ऑब्जेक्ट्स की एक निश्चित संख्या को संयोजित किया जाता है तो स्ट्रिंग क्लास एक कॉन्सटेनेशन ऑपरेशन के लिए बेहतर है। उस स्थिति में, व्यक्तिगत concatenation संचालन भी संकलक द्वारा एक ही ऑपरेशन में जोड़ा जा सकता है। एक स्ट्रिंगबिल्डर ऑब्जेक्ट एक कॉन्सटेनेशन ऑपरेशन के लिए बेहतर है यदि तारों की मनमानी संख्या को समेकित किया जाता है; उदाहरण के लिए, यदि एक लूप उपयोगकर्ता इनपुट के तारों की एक यादृच्छिक संख्या को जोड़ता है।

8

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

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

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

+0

हां! String.Format का उपयोग करें जब ऐसा करने में कोई अर्थ हो, यानी जब आप तारों को स्वरूपित कर रहे हों। जब आप मैकेनिकल कॉन्सटेनेशन कर रहे हों तो स्ट्रिंग कॉन्सटेनेशन या स्ट्रिंगबिल्डर का उपयोग करें। हमेशा उस विधि को चुनने का प्रयास करें जो आपके इरादे को अगले रखरखाव के लिए संचारित करता है। – Rob

-1

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

इस मामले में, मैं स्ट्रिंग का सुझाव दूंगा। फोर्मैट सबसे तेज़ है क्योंकि यह उस सटीक उद्देश्य के लिए डिज़ाइन है।

9

मैं String.Format उम्मीद धीमी होगा - यह तो यह श्रेणीबद्ध स्ट्रिंग और पार्स करने के लिए है।नोटों की

युगल:

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

मैं कुछ त्वरित प्रदर्शन बेंचमार्क भाग गया पूर्वपरिभाषित करने StringBuilder (Int32) निर्माता का उपयोग करें और के लिए 100,000 से अधिक औसत संचालन 10 रन, पहली विधि (स्ट्रिंग बिल्डर) दूसरे (स्ट्रिंग प्रारूप) के लगभग आधे समय लेती है।

तो, यदि यह कम है, तो इससे कोई फर्क नहीं पड़ता। लेकिन अगर यह एक आम ऑपरेशन है, तो आप पहली विधि का उपयोग करना चाह सकते हैं।

3

ओह भी सबसे तेजी से होगा:

string cat = "cat"; 
string s = "The " + cat + " in the hat"; 
+0

नहीं, स्ट्रिंग कॉन्सटेनेशन बेहद धीमी है, क्योंकि .NET इस स्ट्रिंग ऑपरेशंस के बीच आपके स्ट्रिंग चर के अतिरिक्त प्रतियां बनाता है, इस मामले में: दो अतिरिक्त प्रतियां और असाइनमेंट के लिए अंतिम प्रति। परिणाम: 'स्ट्रिंगबिल्डर' की तुलना में बेहद खराब प्रदर्शन जो इस प्रकार के कोडिंग को पहले स्थान पर अनुकूलित करने के लिए बनाया गया है। – Abel

+0

शायद टाइप करने के लिए सबसे तेज़;) – UpTheCreek

+2

@Abel: उत्तर में विवरण की कमी हो सकती है, लेकिन यह दृष्टिकोण इस विशेष उदाहरण में सबसे तेज़ विकल्प है। कंपाइलर इसे एक स्ट्रिंग में परिवर्तित कर देगा। कॉनकैट() कॉल, इसलिए स्ट्रिंगबिल्डर के साथ प्रतिस्थापित करने से वास्तव में कोड धीमा हो जाएगा। –

5

String.Format का उपयोग करता StringBuilder आंतरिक रूप से ... इसलिए तार्किक है कि इस विचार की ओर जाता है कि यह अधिक भूमि के ऊपर की वजह से थोड़ा कम performant होगा। हालांकि, एक साधारण स्ट्रिंग कॉन्सटेनेशन एक महत्वपूर्ण डिग्री से दो अन्य लोगों के बीच एक स्ट्रिंग इंजेक्शन करने का सबसे तेज़ तरीका है। यह साक्ष्य रिको मारियानी ने कई साल पहले अपने पहले प्रदर्शन क्विज़ में प्रदर्शित किया था। सरल तथ्य यह है कि concatenations ... जब स्ट्रिंग भागों की संख्या ज्ञात है (बिना सीमा के..तुम एक हजार भागों को जोड़ सकते हैं ... जब तक आप इसे हमेशा 1000 भागों जानते हैं) ... StringBuilder या स्ट्रिंग से हमेशा तेज .Format। उन्हें एक स्मृति स्मृति आवंटन के साथ एक स्मृति स्मृति आवंटन के साथ किया जा सकता है। Here यहाँ सबूत

है और (परावर्तक के माध्यम से निकाली गई) कुछ String.Concat तरीकों, जो अंततः FillStringChecked फोन जो स्मृति को कॉपी करने के संकेत दिए गए का उपयोग करता है के लिए वास्तविक कोड है:

public static string Concat(params string[] values) 
{ 
    int totalLength = 0; 

    if (values == null) 
    { 
     throw new ArgumentNullException("values"); 
    } 

    string[] strArray = new string[values.Length]; 

    for (int i = 0; i < values.Length; i++) 
    { 
     string str = values[i]; 
     strArray[i] = (str == null) ? Empty : str; 
     totalLength += strArray[i].Length; 

     if (totalLength < 0) 
     { 
      throw new OutOfMemoryException(); 
     } 
    } 

    return ConcatArray(strArray, totalLength); 
} 

public static string Concat(string str0, string str1, string str2, string str3) 
{ 
    if (((str0 == null) && (str1 == null)) && ((str2 == null) && (str3 == null))) 
    { 
     return Empty; 
    } 

    if (str0 == null) 
    { 
     str0 = Empty; 
    } 

    if (str1 == null) 
    { 
     str1 = Empty; 
    } 

    if (str2 == null) 
    { 
     str2 = Empty; 
    } 

    if (str3 == null) 
    { 
     str3 = Empty; 
    } 

    int length = ((str0.Length + str1.Length) + str2.Length) + str3.Length; 
    string dest = FastAllocateString(length); 
    FillStringChecked(dest, 0, str0); 
    FillStringChecked(dest, str0.Length, str1); 
    FillStringChecked(dest, str0.Length + str1.Length, str2); 
    FillStringChecked(dest, (str0.Length + str1.Length) + str2.Length, str3); 
    return dest; 
} 

private static string ConcatArray(string[] values, int totalLength) 
{ 
    string dest = FastAllocateString(totalLength); 
    int destPos = 0; 

    for (int i = 0; i < values.Length; i++) 
    { 
     FillStringChecked(dest, destPos, values[i]); 
     destPos += values[i].Length; 
    } 

    return dest; 
} 

private static unsafe void FillStringChecked(string dest, int destPos, string src) 
{ 
    int length = src.Length; 

    if (length > (dest.Length - destPos)) 
    { 
     throw new IndexOutOfRangeException(); 
    } 

    fixed (char* chRef = &dest.m_firstChar) 
    { 
     fixed (char* chRef2 = &src.m_firstChar) 
     { 
      wstrcpy(chRef + destPos, chRef2, length); 
     } 
    } 
} 

तो फिर:

string what = "cat"; 
string inthehat = "The " + what + " in the hat!"; 

आनंद लें!

+0

, string.Format कैश और एक स्ट्रिंगबिल्डर उदाहरण का पुन: उपयोग करता है ताकि कुछ उपयोगों में तेजी से हो। –

0

यह वास्तव में आपके उपयोग पैटर्न पर निर्भर करता है।
string.Join, string,Concat और string.Format के बीच एक विस्तृत बेंचमार्क यहां पाया जा सकता: String.Format Isn't Suitable for Intensive Logging

6

अगर केवल क्योंकि String.Format वास्तव में आप क्या सोचते हैं हो सकता है ऐसा नहीं करता है, यहाँ परीक्षण 6 साल बाद Net45 पर का फिर से दौड़ना है।

Concat अभी भी सबसे तेज़ है लेकिन वास्तव में यह 30% से कम अंतर है। स्ट्रिंगबिल्डर और प्रारूप मुश्किल से 5-10% से भिन्न है। मुझे कुछ बार परीक्षण चलाने में 20% की विविधताएं मिलीं।

मिलीसेकंड, एक लाख पुनरावृत्तियों:

  • कड़ी: 367
  • न्यू प्रत्येक कुंजी के लिए stringbuilder: 452
  • कैश्ड StringBuilder: 419
  • स्ट्रिंग।प्रारूप: 475

मैं जो पाठ लेता हूं वह यह है कि प्रदर्शन अंतर छोटा है और इसलिए आपको सबसे सरल पठनीय कोड लिखना बंद नहीं करना चाहिए। जो मेरे पैसे के लिए अक्सर होता है लेकिन हमेशा a + b + c नहीं होता है।

const int iterations=1000000; 
var keyprefix= this.GetType().FullName; 
var maxkeylength=keyprefix + 1 + 1+ Math.Log10(iterations); 
Console.WriteLine("KeyPrefix \"{0}\", Max Key Length {1}",keyprefix, maxkeylength); 

var concatkeys= new string[iterations]; 
var stringbuilderkeys= new string[iterations]; 
var cachedsbkeys= new string[iterations]; 
var formatkeys= new string[iterations]; 

var stopwatch= new System.Diagnostics.Stopwatch(); 
Console.WriteLine("Concatenation:"); 
stopwatch.Start(); 

for(int i=0; i<iterations; i++){ 
    var key1= keyprefix+":" + i.ToString(); 
    concatkeys[i]=key1; 
} 

Console.WriteLine(stopwatch.ElapsedMilliseconds); 

Console.WriteLine("New stringBuilder for each key:"); 
stopwatch.Restart(); 

for(int i=0; i<iterations; i++){ 
    var key2= new StringBuilder(keyprefix).Append(":").Append(i.ToString()).ToString(); 
    stringbuilderkeys[i]= key2; 
} 

Console.WriteLine(stopwatch.ElapsedMilliseconds); 

Console.WriteLine("Cached StringBuilder:"); 
var cachedSB= new StringBuilder(maxkeylength); 
stopwatch.Restart(); 

for(int i=0; i<iterations; i++){ 
    var key2b= cachedSB.Clear().Append(keyprefix).Append(":").Append(i.ToString()).ToString(); 
    cachedsbkeys[i]= key2b; 
} 

Console.WriteLine(stopwatch.ElapsedMilliseconds); 

Console.WriteLine("string.Format"); 
stopwatch.Restart(); 

for(int i=0; i<iterations; i++){ 
    var key3= string.Format("{0}:{1}", keyprefix,i.ToString()); 
    formatkeys[i]= key3; 
} 

Console.WriteLine(stopwatch.ElapsedMilliseconds); 

var referToTheComputedValuesSoCompilerCantOptimiseTheLoopsAway= concatkeys.Union(stringbuilderkeys).Union(cachedsbkeys).Union(formatkeys).LastOrDefault(x=>x[1]=='-'); 
Console.WriteLine(referToTheComputedValuesSoCompilerCantOptimiseTheLoopsAway); 
+2

"string.Format ठीक से नहीं करता है जो आप सोच सकते हैं" मेरा मतलब है कि 4.5 स्रोत कोड में यह एक कैश किए गए स्ट्रिंगबिल्डर उदाहरण को बनाने और पुन: उपयोग करने का प्रयास करता है। तो मैंने परीक्षण में उस दृष्टिकोण को शामिल किया –

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