Posted By: travis | Jul 27th, 2004 @ 9:58 AM
page 1 of 2
Comments: 29 | Views: 121765
travis
travis
eo
How many concatenations would it take for StringBuilder to be more useful than a plain old string?

I saw this article in purgatory on codeproject, this msdn blogs post, and this one too.

Any experts want to give it a stab for those of us who don't have time to benchmark every function that concats a string?

Thanks!
rmessier
rmessier
BearBear
Here is my rule of  thumb, anything over like 256 bytes and I go with a stringbuilder, or a loop over more than 4 or 5...

so,

string cFoo = String.Empty;

    cFoo = "Hi";
    cFoo += "there";

but I would use a stringuilder and NOT the += in the following example

for (i=0; i<10; i++)
{
    cFoo += String.Format("Hi {0}",i.ToString());  
}
Dr. Shim
Dr. Shim
Inaniloquent monomathical people inlapidate me.
That's interesting! Are StringBuilders faster for larger data?
ZippyV
ZippyV
Fired Up
Yes. When you use a normal string and change it, the .net framework will destroy the current string in memory and create a new one somewhere else in the memory. With a stringbuilder the object isn't destroyed each time it's adapted.
gabe19
gabe19
bang bang shoot shoot
As far as reasoning, MS docs suggest it is for use in loops.

"The String object is immutable. Every time you use one of the methods in the System.String class, you create a new string object in memory, which requires a new allocation of space for that new object. In situations where you need to perform repeated modifications to a string, the overhead associated with creating a new String object can be costly. The System.Text.StringBuilder class can be used when you want to modify a string without creating a new object. For example, using the StringBuilder class can boost performance when concatenating many strings together in a loop."

So, to answer the question, at what point is it more efficient, I wrote a little tester. The StringBuilder returned Sub-10ms times (DateTime not capable of registering < 10ms) at 1000 or fewer iterations of a loop simply appending the string "string". The += method of concatenation takes 15+ms for the same iterations. At 5000 iterations, the += method was becoming much slower at 218ms. versus the StringBuilder which was still sub 10ms.Even at 10000 iterations, the SB was sub 10, while the concat method had gone over 1.2 seconds. My test code is as follows:

private void UpdateTime()

{

int iterations = Int32.Parse(txtIterations.Text);

string theString = txtTheString.Text;

DateTime strCall = DateTime.Now;

string targetString = null;

for(int x = 0 ; x < iterations ; x++)

{

targetString += theString;

}

TimeSpan time = (DateTime.Now - strCall);

txtConcatTime.Text = time.TotalMilliseconds.ToString();

//StringBuilder

DateTime inCall = DateTime.Now;

StringBuilder sb = new StringBuilder(theString);

for(int x = 0 ; x < iterations ; x++)

{

sb.Append(theString);

}

time = (DateTime.Now - inCall);

txtStringBTime.Text = time.TotalMilliseconds.ToString();

MessageBox.Show("done");

}

jonathanh
jonathanh
My mod color is red
There was a semi-spirited discussion of this very topic on some Microsoft blogs a while back Smiley

I found the blog posts again using "site:blogs.msdn.com string stringbuilder" as a Google query.  
Skibum
Skibum
Enjoying the Off-season
For reference...

The StringBuilder's initial capacity is set to 16 by default.  The capacity then increases by an order of 2 whenever the current capacity is passed.  Therefore, if the String you append to the StringBuilder causes the capacity to expand, it will increase as seen below:

   StringBuilder sb = 
      new System.Text.StringBuilder();
   int capacity = sb.Capacity;

   for (int i=0; i<5000; i++)
   {
    sb.Append("a");
    if (capacity != sb.Capacity)
    {
     PrintLine("Capacity:  " + sb.Capacity);
    }
    capacity = sb.Capacity;
   }

results in the following capacity adjustments:
Capacity: 16
Capacity: 32
Capacity: 64
Capacity: 128
Capacity: 256
Capacity: 512
Capacity: 1024
Capacity: 2048
Capacity: 4096
Capacity: 8192

MisterDonut
MisterDonut
The Disco Godfather
One thing I do to create strings, for smaller ones, but still don't want to concatenate is this:

String.Format("{0}{1}{2}{3}", string1, string2, string3);

Substuting string1-3 with the characters of your choice.

Seems to work pretty well.

MisterDonut wrote:
One thing I do to create strings, for smaller ones, but still don't want to concatenate is this:

String.Format("{0}{1}{2}{3}", string1, string2, string3);

Substuting string1-3 with the characters of your choice.

Seems to work pretty well.



If you crack open String.Format, it creates a StringBuilder internally and uses StringBuilder.AppendFormat to accomplish its goal.

Each call to String.Format results in the the allocation of an instance of StringBuilder - I've only looked at it for two minutes or so, but it appears that StringBuilder.AppendFormat doesn't attempt to estimate the size of the eventual output, so if you're just using it to append strings together, you could find out how large the output is supposed to be and use a StringBuffer with a predetermined capacity to do the appending.

That said, in my own code, I just append the things together for code cleanliness and if that ever shows up in our profiling roadmaps, I'll come back and clean it up.  To date, for at least the work I do, inefficient string appending has been a nonfactor.
Tom Servo
Tom Servo
W-hat?
A StringBuilder does all its operations in a given block of allocated memory. E.g. if you add something to a string, it appends it at the marked end of string, in the same memory block. A regular string operation would allocate a new chunk and copy both strings into the new chunk. It's more work.

However since the StringBuilder needs to be instanced and all that stuff, it's not efficient enough if you're always just quickly adding two strings together, as opposed to for example composing a whole HTML page.
MisterDonut wrote:
String.Format("{0}{1}{2}{3}", string1, string2, string3);




For perf reasons, you should consider String.Concat(string1, string2, string3) instead of the formating.  If it is only called once in your program, it probably doesn't matter, but if you are doing something over and over again, it might be worth looking into the change. 

String.Concat (if I remember correctly) sums up the lengths of all the strings, build a buffer, then places the contents into that buffer.  It only allocates what it needs (different than stringbuilder).

If you are using string builder and you know how about how much space you will need, definitly instantiate it with a default capacity.

I also encourage everyone to look at the Rotor source code to figure out how these things work.  It will help you make informed decisions.  But keep in mind that the Rotor source may be different than the actual MS implementation and the MS implementation could change at any time.

Also, measure perf to make good decisions.
Maurits
Maurits
AKA Matthew van Eerde
travis wrote:

 {
  letterNavText.Append("<a href=\"");
  letterNavText.Append(letter);
  letterNavText.Append(".htm\" title=\"");
  letterNavText.Append(letter);
  letterNavText.Append("\">");
  letterNavText.Append(letter);
  letterNavText.Append("</a>");
 }



I think you can get away with
letterNavText.Append(
    "<a href=\"" + letter + ".htm\" title=\"" + letter + "\">" + letter + "</a>"
);

because multiple string concatenations in a single statement are auto-optimized with an inline StringBuilder replacement.
Hello !

I have got a Problem that is related to this topic.
I have to copy Data from one Database to an Access db and make
some computing during this transfer.

There are quite a lot of records, estimated 40K per table with several tables.

Until now i'm doing the following thing for the inser Operation:

for(int i = 0; i < myDataList.Count; i++) {

cmdText = "INSERT INTO TBLNAME (x,y,z) VALUES "( ";
cmdText += xValue + ", " + yValue + ", " + zValue + " )";

DbWriter.ExecuteNonReader(cmdText);

}

Where DbWriter is a class with static Functions for Capsulating the database connection.

Do you think it would be more useful to use a StringBuilder in this case? I mean the text has to be resetted for every item in the List, so there will be a new StringBuilder Object for every row. Is this still faster?

Best Regards,
  Tim


figuerres
figuerres
???
tim2s wrote:
Hello !

I have got a Problem that is related to this topic.
I have to copy Data from one Database to an Access db and make
some computing during this transfer.

There are quite a lot of records, estimated 40K per table with several tables.

Until now i'm doing the following thing for the inser Operation:

for(int i = 0; i < myDataList.Count; i++) {

cmdText = "INSERT INTO TBLNAME (x,y,z) VALUES "( ";
cmdText += xValue + ", " + yValue + ", " + zValue + " )";

DbWriter.ExecuteNonReader(cmdText);

}

Where DbWriter is a class with static Functions for Capsulating the database connection.

Do you think it would be more useful to use a StringBuilder in this case? I mean the text has to be resetted for every item in the List, so there will be a new StringBuilder Object for every row. Is this still faster?

Best Regards,
  Tim




before the loop create a dbCommand and add a collection of Parameters.  then set the parameter values and call execute.
you will remove a whole bunch of strings ....
 
dbCommand Cmd = new dbCommand( "Insert (x,y,z) values(@Name,@name2..." );
Parameter P1 = new Parameter( "@Name", dbtype);

Cmd.Parameters.Add(P1);

and so on then .. in the loop:

for()
{
P1 =  value;
P2 = other;
P3 = "what";
Cmd.ExecuteNonQuery();
}

no making strings in the loop, and no creating cmd's in a loop.
this makes for nice clean code that runs fast.

Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...

If the thread is that old and your topic is only marginally related, start a new thread.

Anyway, in your case I'd recommend using parameterized queries rather than doing string concatenation at all.

Example:

using( OleDbCommand cmd = connection.CreateCommand() )
{
   cmd.CommandText = "INSERT INTO TBLNAME (x, y, z) VALUES (?, ?, ?)";
   cmd.Parameters.AddWithValue("x", xValue);
   cmd.Parameters.AddWithValue("y", yValue);
   cmd.Parameters.AddWithValue("z", zValue);
   cmd.ExecuteNonQuery();
}


Not only does it remove the need for string concatenation, it eliminates the risk of SQL injection as well.
odujosh
odujosh
Need Microsoft SUX now!
Use a repeater control. Why are using making your own? Smiley
odujosh
odujosh
Need Microsoft SUX now!
travis wrote:

Well, maybe I'll just post my code.  I'm wondering if I should guess the approximate length of a stringbuilder when I create it, or just let it grow dynamically:

System.Text.StringBuilder letterNavText = new System.Text.StringBuilder(1106);
letterNavText.Append("<span>");
for (int i = (int)'A'; i <= (int)'Z'; i++)
{
 string letter = ((char)i).ToString();
 if (letter == SelectedLetter)
 {
  letterNavText.Append("<strong>");
  letterNavText.Append(letter);
  letterNavText.Append("</strong>");
 }
 else
 {
  letterNavText.Append("<a href=\"");
  letterNavText.Append(letter);
  letterNavText.Append(".htm\" title=\"");
  letterNavText.Append(letter);
  letterNavText.Append("\">");
  letterNavText.Append(letter);
  letterNavText.Append("</a>");
 }
 letterNavText.Append("&nbsp;&nbsp;");
}
letterNavText.Append("</span>");
LetterNav.InnerHtml = letterNavText.ToString();



Previous post referred to this little nugget. Sorry one of my pet peeves. If you want it I can post a sample that does just this using a repeater.
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
For a stringbuilder, a constant "cost" of expanding the capacity is linear w.r.t the previous capacity.

If you choose your initial value for the StringBuilder capacity carefully, it is nearly always the most efficient solution.


So.

For small or strictly constant strings, System.String is valid. For large strings, construction of strings other than with String.Format() or for strings which need to change quickly and can be large (e.g. the Value field in a text-editor or syntax editor), use a System.StringBuilder.

In the event that you want to be able to change text even faster (or holding really big values), then you'll start needing to construct your own data types over this (e.g. a linked-list of stringbuilders is more efficient for insertion than a mege-stringbuilder, both of which are vastly better than a System.String).
dbCommand Cmd = new dbCommand( "Insert (x,y,z) values(@Name,@name2..." );
Parameter P1 = new Parameter( "@Name", dbtype);

Cmd.Parameters.Add(P1);

and so on then .. in the loop:

for()
{
P1 =  value;
P2 = other;
P3 = "what";
Cmd.ExecuteNonQuery();
}

no making strings in the loop, and no creating cmd's in a loop.
this makes for nice clean code that runs fast.


Thank you,

but i write into an *.mpl, which can not be used with the incredible SqlConnction. I have to fight with strings into an OleDb.

But maybe i can convince them to use an Sql Express Db Wink
figuerres
figuerres
???
tim2s wrote:
dbCommand Cmd = new dbCommand( "Insert (x,y,z) values(@Name,@name2..." );
Parameter P1 = new Parameter( "@Name", dbtype);

Cmd.Parameters.Add(P1);

and so on then .. in the loop:

for()
{
P1 =  value;
P2 = other;
P3 = "what";
Cmd.ExecuteNonQuery();
}

no making strings in the loop, and no creating cmd's in a loop.
this makes for nice clean code that runs fast.


Thank you,

but i write into an *.mpl, which can not be used with the incredible SqlConnction. I have to fight with strings into an OleDb.

But maybe i can convince them to use an Sql Express Db


well i would go for sql express for many reasons but...

System.Data.OleDb.OleDbCommand odb = new System.Data.OleDb.OleDbCommand("");
odb.Parameters.Add();

I think the ole db parpameter makers are '?' in place of '@name'
but the rest should I think work with oledb as well as sql, and I think odbc supports parameters also.

stevo_
stevo_
Human after all

Please don't do that.

foreachdev
foreachdev
Twitter: @foreachdev
My general rule of thumb is to use string concatenation or string.Format up to  3 concats. Afterwhich I will go to the trouble of using a string builder or some kind of stream writer. I remember reading that string concats are more performat up to 3 concats then it goes south from there.

Probably unless your doing fairly intensive concating it won't be that big of deal. Most devs I work with brush it off.
page 1 of 2
Comments: 29 | Views: 121765
Microsoft Communities