Efficient string concatenation

by Dominic Zukiewicz 17. April 2007 12:41

Its always a good thing to know how to get the very best out of .NET. One area that is always overlooked is string concatenation. You have several ways to do this including:

  • string x = "HELLO" + " " + "THERE";
  • string x = "HELLO "; x = x + "THERE";
  • string x = "HELLO "; x += "THERE";
  • string x = String.Concat("HELLO"," ","THERE");

Although these are syntactically correct, they eat memory up faster than a buffet lunch at a fat fighters convention!

This is the process that is carried out by the application:

string text = text + otherText;
  1. Allocates temporary memory large enough to hold the result.
  2. Copies text to the start of the temporary area.
  3. Copies otherText to the end of the temporary area.
  4. De-allocates the old copy of text.
  5. Allocates memory for text large enough to hold the result.
  6. Copies the temporary data to text.

The best and fastest way by far is the StringBuilder class. The class allows the addition of data via the .Append() and .AppendFormat() methods. Below I have placed some statistics of the concatentation process on my machine. This test appended the string ABCDEFGHIJKLMNOPQRSTUVWXYZ to itself the specified number of times.

Method Iterations Time taken (s)
+= 1000 0.046875
String.Concat() 1000 0.046875
StringBuilder.Append() 1000 0.0
 
+= 2000 0.3125
String.Concat() 2000 0.375
StringBuilder.Append() 2000 0.0
 
+= 4000 2.34375
String.Concat() 4000 2.359375
StringBuilder.Append() 4000 0.0
 
+= 8000 8.984375
String.Concat() 8000 9
StringBuilder.Append() 8000 0.015625
 
+= 16000 31.546875
String.Concat() 16000 31.015625
StringBuilder.Append() 16000 0.03125

As you can see the values are going up exponentially for the previous 2 methods, whereas the .Append methods are still extremely fast!

Give it a try. Here is the code I used.

using System;
using System.Collections.Generic;
using System.Text;

namespace StringAppending
{
    class Program
    {
        const string TEXT = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        static void Main(string[] args)
        {
            System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Highest;

            int[] iterations = new int[] { 1000, 2000, 4000, 8000, 16000 };
            Console.WriteLine("Testing String comparisons.");

            string[] headings = new string[] { "Method".PadRight(20), "Iterations".PadRight(20), "Time Taken (s)".PadRight(20) };
            string[] tests = new string[] { "+=".PadRight(20), "String.Concat".PadRight(20), "StrBuilder.Append".PadRight(20) };

            for (int counter = 0; counter < iterations.Length; counter++)
            {
                string iterationString = iterations[counter].ToString().PadRight(20);

                double test1Result = StringPlus(iterations[counter]).TotalSeconds;
                double test2Result = StringConcat(iterations[counter]).TotalSeconds;
                double test3Result = StringAppend(iterations[counter]).TotalSeconds;

                Console.WriteLine("Iterations: {0}\n====================", iterationString);
                Console.WriteLine("{0}{1}{2}", headings[0], headings[1], headings[2]);
                Console.WriteLine("{0}{1}{2}", tests[0], iterationString, test1Result);
                Console.WriteLine("{0}{1}{2}", tests[1], iterationString, test2Result);
                Console.WriteLine("{0}{1}{2}", tests[2], iterationString, test3Result);
                Console.WriteLine("");
            }
            Console.Read();
        }

        private static TimeSpan StringPlus(int iterations)
        {
            DateTime start = DateTime.Now;

            string textToAppend = TEXT;
            string content = string.Empty;

            int totalIterations = iterations * textToAppend.Length;

            for (int counter = 0; counter < iterations; counter++)
            {
                content += textToAppend;

                if (counter % 100 == 0)
                    Console.Write("{0:P} complete.   (1/3) \r", ((float)content.Length / totalIterations));
            }

            return DateTime.Now.Subtract(start);
        }

        private static TimeSpan StringConcat(int iterations)
        {
            DateTime start = DateTime.Now;

            string textToAppend = TEXT;
            string content = string.Empty;

            int totalIterations = iterations * textToAppend.Length;

            for (int counter = 0; counter < iterations; counter++)
            {
                content = String.Concat(content, textToAppend);

                if (counter % 100 == 0)
                    Console.Write("{0:P} complete.   (2/3)\r", ((float)content.Length / totalIterations));
            }

            return DateTime.Now.Subtract(start);
        }

        private static TimeSpan StringAppend(int iterations)
        {
            DateTime start = DateTime.Now;

            string textToAppend = "";

            int totalIterations = iterations * textToAppend.Length;
            StringBuilder content = new StringBuilder();

            for (int counter = 0; counter < iterations; counter++)
            {
                content.Append(textToAppend);

                if (counter % 100 == 0)
                    Console.Write("{0:P} complete.   (3/3)\r", ((float)content.Length / totalIterations));
            }

            return DateTime.Now.Subtract(start);
        }
    }
}

Tags:

Framework

Powered by BlogEngine.NET 1.5.0.7
Theme by Interakting

Interakting

A full service digital agency offering online strategy, design and usability, systems integration and online marketing services that deliver real business benefits and ensure your online objectives are met.

Calendar

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar