Jeff and .NET

The .NET musings of Jeff Putz

Sponsors

News

My Sites

Check my code: StringBuilder vs. concatenation

I think I did this right, but give it a look. I'm trying to demonstrate the benefit of using StringBuilder over straight string concatenation. The two loops are functionally equivalent, right?

string sentence = "I really like riding roller coasters because they're super fun and have ups and downs, just like life!";
string[] words = sentence.Split(new char[] { ' ' });
string result = "";
Trace.Warn("Start concatenation");
for (int i = 0; i < 1000; i++)
{
 foreach (string word in words)
 {
  result = result + word + " ";
 }
}
Trace.Warn("End concatenation");
Trace.Warn("Start StringBuilder");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
 foreach (string word in words)
 {
  builder.Append(word);
  builder.Append(" ");
 }
}
result = builder.ToString();
Trace.Warn("End StringBuilder");

If you're interested, the trace times looked like this:

Start concatenation 0.000157
End concatenation 22.377516
Start StringBuilder 0.000212
End StringBuilder 0.013082
Posted: Aug 15 2004, 08:24 PM by Jeff | with 12 comment(s)
Filed under:

Comments

Geoff Appleby said:

Looks good to me. Stringbuilder kicks ass, doesn't it? :)
# August 15, 2004 10:49 PM

Chad Myers said:

I'm more curious about AppendFormat(). How big of a hit does that take out of the works?

For example:

builder.AppendFormat("{0} \n", word);
# August 16, 2004 12:51 AM

Eric Newton said:

well, APpendFormat is obviously using String.Format under the hood, so there's a cost factor involved in tokenizing the "Format string" and inserting the values into the resulting string [which ironically uses StringBuilder itself! go figure... kinda like Alabama cousins]

Supposedly you can also use a string[] to build a set of strings, typically staggered as literal/changable/literal/changable etc and it's even faster than stringbuilder:

<code>
string[] full = new string[1000];
string[] test = new string[5];
for(int i=0; i <= 1000; i++)
for( int j=0; j <= 1000; j++ )
{
test[0] = "The current value of I is ";
test[1] = i.ToString();
test[2] = ". The current value of J is ";
test[3] = j.ToString();
test[4] = ".\n";
}
full[i] = string.Concat(test);
}
Console.WriteLine(string.Concat(full));
</code>
# August 16, 2004 2:20 AM

Aapo Laakkonen said:

In Java World there used to be huge debates whether to use string concatenation or StringBuffer class. Currently as Java compilers have got more mature these conversations doesn't arise as often as they used to. And, yes you get same performance with both techniques. Java Compilers replace repetive string concatenations with string buffers. I see no reason why this feature has not been implemented in .NET. If you ask me, StringBuffers have no use if you have compiler smart enough to deal with this issue.
# August 16, 2004 4:48 AM

Darrell said:

Jeff - works great if you have a developer that is actually going to append 1000 strings on different lines of code (hopefully even the slightest code review would catch that). If you have a lot of concatenations using the + command you will see using reflector that only 1 concat is called under the hood.

At some point in time the overhead of StringBuilder outweighs its usefulness. That is the point around which guidance need be given. I've heard somewhere around 5-10 concats is where StringBuilder gains enough of an advantage to use it. Your mileage may vary.
# August 16, 2004 10:35 AM

David Hayden said:

I can't agree more with Darrell.

A lot of the "religious" wars have to do with performance. We always here - don't use dynamic SQL, use stored procedures. Don't use foreach, use a for loop. Don't concatenate, use StringBuilder. Don't use the DataSet, use the DataReader. Don't access DataRow fields by column name, access them by index, don't use O/R Mappers, build your own data layer, etc., etc., etc.

Certainly it is important to know the trade-offs in performance when building the application, but it is important to know at what point one actually sees a performance hit and understand that the performance hit may be acceptable from a maintainability and cost standpoint.

Not every website is Match.com. Not every application is SAP.

You seem like a very pragmatic developer, so I suspect you will touch on those areas of reality when appropriate.
# August 16, 2004 12:20 PM

Nat Luengnaruemitchai said:

Try...

string.Join(" ",words) instead of the inner loop. Might be even faster :)
# August 16, 2004 1:19 PM

Jim Hughes said:

To be even more dramatic (and line by line code equivalent):

result = result + word + " ";

should read

result = result + word;
result = result + " ";

It's not fair to optimize the "bad" code! After all, the StringBuilder has to do it in two lines!

With my proposed change:

Before:
00:00:17.9078928
00:00:00.0100156

After
00:00:35.7356608
00:00:00.0100156
# August 16, 2004 1:53 PM

TrackBack said:

# August 16, 2004 3:31 PM

Frans Bouma said:

However:
string f = "Foo";
string b = "Bla";
string s = f + b;
beats:
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}{1}", f, b);

Stringbuilder is not always 'the right way' ;)
# August 16, 2004 3:41 PM

CumpsD said:

Chad, AppendFormat is something I'd avoid when you are talking about performance, since it'll first parse the format string for {x} instances and then call .Append() on the stringbuilder anyway. You're better of calling Append multiple times yourself if you only need to put in some variables without formating.

I've just done some tests on the memory usage of various concatenation methods which can help make things even more clear: blog.cumps.be/string-concatenation-vs-memory-allocation

In the end, it comes down to the amount of strings to concatenate to decide between a StringBuilder or String.Concat (+'ing strings together translates into String.Concat calls under the hood)

# September 16, 2007 2:19 PM

Khurram shahzad said:

thanks

i got a good idea

# September 27, 2008 12:11 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)