To list available contexts: kubectl config get-contexts To show the current context: kubectl config current-context…
StringBuilder is not always faster – Part 1 of 2
How often have you been told to use StringBuilder to concatenate strings in .NET? My guess is often enough. Here is something you may not know about string concatenation: StringBuilder is not always faster. There are already many articles out there that explain the why’s, I am not going to do that here. But I do have some test data for you.
When concatenating three values or less, traditional concatenation is faster (by a very small margin)
This block of code took 1484 milliseconds to run on my PC:
for (int i = 0; i <= 1000000; i++) { // Concat strings 3 times using StringBuilder StringBuilder s = new StringBuilder(); s.Append(i.ToString()); s.Append(i.ToString()); s.Append(i.ToString()); }
And this one, using traditional concatenation, took slightly less time (1344 milliseconds):
for (int i = 0; i <= 1000000; i++) { // Concat strings 3 times using traditional concatenation string s = i.ToString(); s = s + i.ToString(); s = s + i.ToString(); }
The above data suggests that StringBuilder only starts to work faster once the number of concatenations exceed 3.
Building strings from literals
When building a large string from several string literals (such as building a SQL block, or a client side javascript block), use neither traditional concatenation nor StringBuilder. Instead, choose one of the methods below:
+ operator
// Build script block string s = "<script>" + "function test() {" + " alert('this is a test');" + " return 0;" + "}";
The compiler concatenates that at compile time. At run-time, that works as fast as a big string literal.
@ string literal
I sometimes use the @ string literal which allows for newlines (I find this syntax is harder to maintain, formatting-wise, than using the + operator):
string s = @"<script> function test() { alert('this is a test'); return 0; }";
Both methods above run about 40 times faster than using StringBuilder or traditional string concatenation.
Rules of Thumb
- When concatenating three dynamic string values or less, use traditional string concatenation.
- When concatenating more than three dynamic string values, use StringBuilder.
- When building a big string from several string literals, use either the @ string literal or the inline + operator.
Updated 2007-09-29
I have posted a follow-up article to provide more detailed analysis and to answer some of the questions asked by readers.
What about string.Concat() ?
–larsw
I don’t find this argument very convincing.
It is well known and pretty obvious that the compiler will concatenate string literals at compile time. But good to point it out again.
But the rule of thumb on three dynamic values seems way too vague. What if each dynamic value results in strings 4,000 characters long? Why 3? Did you compare the above two loops with 4 values or more? What is the IL doing in those loops? Is it possible the JIT is noticing you never use the generated objects and just not creating them at all?
Matt: Good questions and thanks for asking. In my tests (I only included one test in the article), once the number of concats goes to 4, then the StringBuilder operations started to work faster.
I also thought about the possible JIT optimizations but honestly I did not look at what the IL was doing. I purposefully included the dynamic loop variable “i” in the concatenations to make sure the compiler did not “optimize away” the code. However, I will do some analysis into the generated IL for some definite answers.
Lars: I didn’t even know about string.Concat before today. It appears to be a better way to concatenate up to four dynamic strings than the “+” operator because it allocates memory for all the values in advance. I hope to shed some more light on string.Concat in a follow-up article.
@Chinh Do: string.Concat is not _better_ than “+”, it’s identical. If you write “string s= a + b + c;” the compiler will actually emit “string s= string.Concat(a,b,c);”. It has to be one statement though, which is one reason why your sample loop didn’t use it.
Have a look at http://ajdotnet.wordpress.com/2007/05/20/about-the-virtue-of-not-improving-performance/ for details.
Regarding the “stringbuilder in loop” example: There may be cases when you cannot avoid such code. It may however be improved by allocating the stringbuilder before the loop and reusing it.
HIH,
AJ.NET
Interesting article! I’ve done some research on string performance this week as well, in case you’re interested: http://blog.cumps.be/string-concatenation-vs-memory-allocation/
What about String.Format(“{0}{1}”,string1,string2);
?
AJ.NET: Thanks for the info re string.Concat. That’s nice to know.
Re the “for” loop, that’s there intentionally and it’s not part of what I wanted to measure… it’s there to measure multiple times for a more accurate final result. If I didn’t have the for loop, the operation would probably too fast to measure accurately.
Flyswat: I have not looked at string.Format vs “+”. I hope to experiment some and will post back here with the results.
[…] Do has posted two good articles this week: StringBuilder is not always faster ~ 11 VS 2005 IDE […]
[…] a previous article (”StringBuilder is not always faster), I provided some quick benchmark data and gave “rules of thumb” for when to use […]
Hello all, I have posted a follow-up article to provide more detailed analysis and to answer some of the questions asked by readers.
[…] StringBuilder is not always faster StringBuilder is not always faster – Part 2 […]
If .Net handles String and StringBuilder like Java does, the reason that 3 is the break even point has to do with object creation. With 3 concatenations, each method creates 5 objects (by my count).
StringBuilder:
1 StringBuilder
3 Strings for input
1 String for the final result
Concatenation:
3 Strings for input
1 String for the result of the concatenation of String 2 + 3
1 String for the result of the concatenation of String 1 and the above
Michael: That makes a lot of sense. Thanks.
‘###
This block of code took 1484 milliseconds to run on my PC:
for (int i = 0; i <= 1000000; i++)
{
// Concat strings 3 times using StringBuilder
StringBuilder s = new StringBuilder();
s.Append(i.ToString());
s.Append(i.ToString());
s.Append(i.ToString());
}
And this one, using traditional concatenation, took slightly less time (1344 milliseconds):
for (int i = 0; i <= 1000000; i++)
{
// Concat strings 3 times using traditional concatenation
string s = i.ToString();
s = s + i.ToString();
s = s + i.ToString();
}
The above data suggests that StringBuilder only starts to work faster once the number of concatenations exceed 3.
‘###
I noticed in the ‘string’ example you initialize s with the first string. Would StringBuilder be equivalent or faster for 3 concatenations if you initialized stringbuilder also with the first string? e.g. result in 3 lines instead of 4:
StringBuilder s = new StringBuilder(i.ToString(),16);
s.Append(i.ToString());
s.Append(i.ToString());
*Note StringBuilder Initializer includes default size of 16, otherwise it would be reallocating memory with each append since the size would also initialize to 1.
Marvin: Good question. Thanks. I am curious about it too so I decided to run some measurements again. My result indicates that doing the initialization like you suggested will save some time off of the StringBuilder result. However it was not enough to be faster than the string test. Seems like it would be a good idea to always seed the initial value as part of the construction if you can do it.
Chinh
Use a MemoryProfiler to see which one is better
In the end, it depends on the specific case.
In most cases, that little margin is only in theory relevant – and if that would be important to you, you may be better off with another language/framework.
For enterprise apps, maintainability and quality is much more important than the very last lightspeed seconds, i’d say.
Sure, some webpages may be experience an improvement in their html-output speed, but its always a trade off…
Read this article which focuses on the ‘why’ aspect.
http://www.codetails.com/punitganshani/why-is-stringbuilder-faster-in-string-concatenations/20121030
[…] From Chinh Do – StringBuilder is not always faster: […]
[…] From Chinh Do – StringBuilder is not always faster: […]