Chinh Do

StringBuilder is not always faster – Part 1 of 2

24th February 2007

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.

This entry was posted on Saturday, February 24th, 2007 at 1:13 am and is filed under Dotnet/.NET - C#, Programming. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

There are currently 20 responses to “StringBuilder is not always faster – Part 1 of 2”

  1. 1 On September 18th, 2007, Lars Wilhelmsen said:

    What about string.Concat() ?

    –larsw

  2. 2 On September 18th, 2007, Matt said:

    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?

  3. 3 On September 18th, 2007, Chinh Do said:

    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.

  4. 4 On September 18th, 2007, Chinh Do said:

    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.

  5. 5 On September 19th, 2007, AJ.NET said:

    @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

  6. 6 On September 21st, 2007, David Cumps said:

    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/

  7. 7 On September 21st, 2007, Flyswat said:

    What about String.Format(“{0}{1}”,string1,string2);

    ?

  8. 8 On September 23rd, 2007, Chinh Do said:

    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.

  9. 9 On September 23rd, 2007, Weekly Link Post 8 « Rhonda Tipton’s WebLog said:

    [...] Do has posted two good articles this week: StringBuilder is not always faster ~ 11 VS 2005 IDE [...]

  10. 10 On September 29th, 2007, StringBuilder is not always faster - Part 2 » Chinh Do said:

    [...] a previous article (”StringBuilder is not always faster), I provided some quick benchmark data and gave “rules of thumb” for when to use [...]

  11. 11 On September 29th, 2007, Chinh Do said:

    Hello all, I have posted a follow-up article to provide more detailed analysis and to answer some of the questions asked by readers.

  12. 12 On September 29th, 2007, 1kHz | anti-keseronokan » Blog Archive » String Concatenation dan Performance said:

    [...] StringBuilder is not always faster StringBuilder is not always faster – Part 2 [...]

  13. 13 On March 14th, 2008, YuzeroK said:

    Хороший заработок в интернете. Нужно покоментировать страницы, которые вам откроют после регистрации, и за это платят денги и не малые. Я лично зарабатываю около 500$ в месяц.

    Регистрируемся тут awsurveys.com

    1.Нажимите Create A Free Account

    UserName – имя пользователя
    Password – пароль 7-15 знаков
    First Name – имя
    Last Name – Фамилия
    Email Address – почтовый ящик
    Далее вводим цифорки-буковки, нажимаем кнопку Create A Free Account
    Вы зарегистрировались!

    2.Далее видим таблицу, имеющую такой вид:

    The Following Surveys are Available:
    Welcome Survey — A $6.00 Website Evaluation is Available.
    A $4.00 Website Evaluation is Available.
    A $4.00 Website Evaluation is Available.
    A $4.00 Website Evaluation is Available.
    A $4.00 Website Evaluation is Available.
    A $4.00 Website Evaluation is Available.

    3.Щелкаем по одной из ссылок на этой странице, попадаем на следущюю страницу и там щелкаем по надписи “Start Survey Now”

    4.Здесь 2 ссылки и 2 поля, в них нужно написать отзыв о сайте на англ языке.

    (пример: It is an excellent site, I shall advise its all, this is good job, it’s very usefull web-resource и т.п)

    5.Щелкае по кнопке внизу “Click to submit …” Щелкаем по ссылке “Click Here to go Home and…”

    6.И так далее по ссылкам и так каждый день.

    7.Для вывода денег воспользуйтесь кнопкой “Redeem Money”
    выводятся деньги в системе PayPal (легко переводятся в вебмани)
    могу помочь тем кто не знаком с электронными платежными системами

  14. 14 On April 20th, 2009, Michael said:

    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

  15. 15 On April 20th, 2009, Chinh Do said:

    Michael: That makes a lot of sense. Thanks.

  16. 16 On April 23rd, 2009, Marvin said:

    ‘###
    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.

  17. 17 On April 24th, 2009, Chinh Do said:

    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

  18. 18 On July 7th, 2009, Trevor said:

    Use a MemoryProfiler to see which one is better

  19. 19 On August 15th, 2012, Lelala said:

    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…

  20. 20 On December 11th, 2012, Sam said:

    Read this article which focuses on the ‘why’ aspect.

    http://www.codetails.com/punitganshani/why-is-stringbuilder-faster-in-string-concatenations/20121030

Leave a Comment

*