TheDeveloperBlog.com


C# StringBuilder Optimization Tip

StringBuilder optimization. It is possible to optimize the StringBuilder Append method. This applies to certain cases that deal with short strings. Instead of appending a string literal that contains two characters, we append two characters separately.

Warning: This optimization does not consistently work. It seems to work on 32-bit systems and not on 64-bit systems.

Thus: Its use is discouraged unless you have tested it on the target computer. Otherwise it may slow things down.


Example. This program benchmark harness demonstrates how you can express a two-character append operation in two different ways. In the first tight loop, two space characters are appended in separate method calls.

Char Type

And: In the second tight loop, a two-character string is appended in a single method call. The first loop has better performance.

C# program that tests StringBuilder optimization tip

using System;
using System.Diagnostics;
using System.Text;

class Program
{
    const int _max = 10000000;
    static void Main()
    {
	StringBuilder builder = new StringBuilder();
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    // Append two characters.
	    builder.Append(' ');
	    builder.Append(' ');
	}
	s1.Stop();
	builder = new StringBuilder();
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    // Append two characters combined into a string.
	    builder.Append("  ");
	}
	s2.Stop();
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Output

12.99 ns
15.29 ns

The reason. The string type in the C# language has some complexities that characters do not have. A char type is represented by a small integer, while a string type must be allocated on the managed heap and have its own memory location.

String Memory

The string type is a full-fledged object. But the char type is only a number. To resolve the string argument in Append, the StringBuilder must reference all the characters separately.

However: The control path for the char overload is more direct and therefore faster.

At some point, using separate character appends will slow down the method you are writing. I found using chars for 1, 2, 3 and often 4 character long strings was more efficient. Longer than that and the strings were more efficient.

Note: This may involve locality of reference or simply better string copying routines, such as those that unroll loops and use unsafe code.

The Response.Write method (from ASP.NET) can use this same optimization and the results are sometimes more pronounced. I tested it. I found that single-character writes were faster in sequences of two than two-character string writes.

Response.Write

Summary. We looked at one way you can perform micro-optimizations on the StringBuilder type in the C# language. This is not a dramatic performance boost in many cases where StringBuilder is used.

But: This optimization can provide a measurable speedup to StringBuilder code as well as Response.Write code.

StringBuilder Data Types