|
July 9th, 2002
In most .NET performance articles you will read the tip to use
the StringBuilder class for string concatenation. In this article you will
learn whether and when this statement is valid.
Introduction
Take any article dealing with performance issues in .NET applications and in
most cases you will read that it is advisable to use the
StringBuilder
class (namespace:
System.Text) for string concatenations. However,
regardless of all advantages the
StringBuilder
class has, from the programmer's perspective it is less comfortable than
operator (+) concatenation (be it only that you need to create a new instance
of that class). In that context, the question arises whether or not it is always
necessary to use the
StringBuilder. The intuition is that for only few
concatenation statements it shouldn't matter. I decided to find out if the
intuition is right and performed a series of tests to that end.
Methodology
In the performance test two contatenation methods were analysed: operator (+)
concatenation and
StringBuilder
concatenation.
In order to simulate different real-world scenarios, for every concatenation method
- a different number of concatenations
- of different-length strings
were analyzed.
The tests were performed by means of a console application on a Dell Latitude C500 Notebook with 384MB RAM.
The number of concatenations was based on the powers 0-12 of 2 (1, 2, 4, 8, ..., 4096).
For each number of concatenations three string
lenghts were used (10, 100 and 1000). One test consisted of all possible
combinations of the two parameters mentioned. Five such tests were performed and
averages computed.
Below is the source code of the console application used for the test.
By changing the first four variables, you can adapt the string lengts and iteration steps to your needs.
- Code for the performance tests
-
using System; using System.Text; using System.IO; namespace PerformanceTests { class Concatenation { private static int IterationsMaxPower = 12; private static int IterationsPowerBase = 2; private static int StringLenMaxPower = 3; private static int StringLenPowerBase = 10; [STAThread] static void Main(string[] args) { CommaSeparated(); } private static void CommaSeparated() { int IterationsCount; string StrToConcatenate = String.Empty; string Buffer; DateTime start; DateTime end; TimeSpan DurationPlus = TimeSpan.Zero; TimeSpan DurationStringBuilder = TimeSpan.Zero; Console.WriteLine("Number of Iterations,String Length,Duration Plus Method [ticks],Duration StringBuilder Method [ticks]"); for (int IterationsPower = 0; IterationsPower <= IterationsMaxPower; IterationsPower++) { IterationsCount = (int) Math.Pow((double) IterationsPowerBase, (double) IterationsPower); for (int StringLenPower = 0; StringLenPower <= StringLenMaxPower; StringLenPower++) { Buffer = String.Empty; StrToConcatenate = new String('#', (int) Math.Pow((double) StringLenPowerBase, (double) StringLenPower)); // + Concatenation // Timer on start = DateTime.Now; for (int Iteration = 1; Iteration <= IterationsCount; Iteration++) { Buffer += StrToConcatenate; } // Timer off end = DateTime.Now; DurationPlus = end - start; Buffer = String.Empty; // StringBuilder Concatenation // Timer on start = DateTime.Now; StringBuilder sb = new StringBuilder(IterationsCount); for (int Iteration = 1; Iteration <= IterationsCount; Iteration++) { sb.Append(StrToConcatenate); } Buffer = sb.ToString(); // Timer off end = DateTime.Now; DurationStringBuilder = end - start; Console.WriteLine("{0},{1},{2},{3}", IterationsCount, StrToConcatenate.Length, DurationPlus.Ticks, DurationStringBuilder.Ticks); } } } } }
Results
The table below summarizes the results of the performance tests. Each figure is an average of the five tests (see Methodology).
| # Iterations |
String Length |
Duration |
| Plus [ticks] |
StringBuilder [ticks] |
| 1 |
1 |
0.0 |
0.0 |
| 1 |
10 |
0.0 |
0.0 |
| 1 |
100 |
0.0 |
0.0 |
| 1 |
1000 |
0.0 |
0.0 |
| 2 |
1 |
0.0 |
0.0 |
| 2 |
10 |
0.0 |
0.0 |
| 2 |
100 |
0.0 |
0.0 |
| 2 |
1000 |
0.0 |
0.0 |
| 4 |
1 |
0.0 |
0.0 |
| 4 |
10 |
0.0 |
0.0 |
| 4 |
100 |
0.0 |
0.0 |
| 4 |
1000 |
0.0 |
0.0 |
| 8 |
1 |
0.0 |
0.0 |
| 8 |
10 |
0.0 |
0.0 |
| 8 |
100 |
0.0 |
0.0 |
| 8 |
1000 |
40057.6 |
0.0 |
| 16 |
1 |
0.0 |
0.0 |
| 16 |
10 |
0.0 |
0.0 |
| 16 |
100 |
0.0 |
0.0 |
| 16 |
1000 |
40057.6 |
0.0 |
| 32 |
1 |
0.0 |
0.0 |
| 32 |
10 |
0.0 |
0.0 |
| 32 |
100 |
20028.8 |
0.0 |
| 32 |
1000 |
80115.2 |
0.0 |
| 64 |
1 |
20028.8 |
0.0 |
| 64 |
10 |
0.0 |
0.0 |
| 64 |
100 |
0.0 |
0.0 |
| 64 |
1000 |
380547.2 |
20028.8 |
| 128 |
1 |
0.0 |
0.0 |
| 128 |
10 |
0.0 |
0.0 |
| 128 |
100 |
100144 |
0.0 |
| 128 |
1000 |
1782563.2 |
40057.6 |
| 256 |
1 |
20028.8 |
0.0 |
| 256 |
10 |
20028.8 |
0.0 |
| 256 |
100 |
480691.2 |
0.0 |
| 256 |
1000 |
7691059.2 |
100144 |
| 512 |
1 |
20028.8 |
0.0 |
| 512 |
10 |
120172.8 |
20028.8 |
| 512 |
100 |
2223196.8 |
0.0 |
| 512 |
1000 |
32026051.2 |
200288 |
| 1024 |
1 |
100144 |
0.0 |
| 1024 |
10 |
600864 |
0.0 |
| 1024 |
100 |
10595235.2 |
40057.6 |
| 1024 |
1000 |
127383168 |
480691.2 |
| 2048 |
1 |
220316.8 |
0.0 |
| 2048 |
10 |
2703888 |
40057.6 |
| 2048 |
100 |
47908889.6 |
60086.4 |
| 2048 |
1000 |
506027632 |
881267.2 |
| 4096 |
1 |
861238.4 |
20028.8 |
| 4096 |
10 |
13739756.8 |
20028.8 |
| 4096 |
100 |
202250822.4 |
180259.2 |
| 4096 |
1000 |
1992705370 |
1782563.2 |
Note: A tick is equal to 100 nanoseconds.
Anotherwords, one second equals 10 million ticks.
E.g., concatenating a 100-character string 2048 times took 4.7 seconds with the operator (+) methods whereas it took 0.002 second with the StringBuilder method.
Findings
- Up to four iterations the concatenation method is irrelevant.
This applies for 1-character strings as well for 1000-character strings.
- For short strings (1 to 10 characters) and up to 128 iterations the concatenation method is irrelevant.
- The longer the string to concatenate, the greater the relative advantage of the StringBuilder method over the operator (+) method.
With growing number of iterations for the same string length, the relative advantage of the StringBuilder method grows too.
E.g., concatenating a 1000-character string 128 times with the operator (+) method takes 44 times more time than with the StringBuilder method;
concatenating the same string 4096 times with the operator (+) method is 1118 times longer than with the StringBuilder method.
At the same time, the StringBuilder method is "only" 43 times faster than the operator (+) method when concatenating 1-character strings 4096 times.
If you have any comments, please feel free to air them (Feedback button).
|