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.

Chinh Do

I occasionally blog about programming (.NET, Node.js, Java, PowerShell, React, Angular, JavaScript, etc), gadgets, etc. Follow me on Twitter for tips on those same topics. You can also find me on GitHub. See About for more info.

View Comments

  • '###
    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

  • 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...

Recent Posts

How to switch to a different Kubernetes context or namespace?

To list available contexts: kubectl config get-contexts To show the current context: kubectl config current-context…

2 years ago

How to ssh into Kubernetes pod

kubectl exec -it <podname> -- sh To get a list of running pods in the…

2 years ago

How to Create a Soft Symbolic Link (symlink) in Unix/Linux

# Create a soft symbolic link from /mnt/original (file or folder) to ~/link ln -s…

3 years ago

How to Configure Git Username and Email Address

git config --global user.name "<your name>" git config --global user.email "<youremail@somewhere.com>" Related Commands Show current…

3 years ago

Getting the Last Monday for Any Month with TypeScript/JavaScript

TypeScript/JavaScript function getLastMonday(d: Date) { let d1 = new Date(d.getFullYear(), d.getMonth() + 1, 0); let…

4 years ago

How to View Raw SMTP Email Headers in Outlook

I had to do some SMTP relay troubleshooting and it wasn't obvious how to view…

5 years ago