16.2. Speeding up String Concatenation with a StringBuilder

Problem

You want to reduce the time spent concatenating strings in an application that performs this operation repeatedly.

Solution

Concatenate strings with a StringBuilder object instead of the classic & and + concatenation operators.

Example 16-4 through Example 16-6 show the .aspx file and the VB and C# code-behind files for our application that demonstrates the performance difference between using the classic string operators and a StringBuilder object to perform concatenation. Our example concatenates two strings repeatedly, and then calculates the average time per concatenation for the two approaches. The output of the application is shown in Figure 16-1.

Measuring string concatenation performance output

Figure 16-1. Measuring string concatenation performance output

Discussion

In the common language runtime (CLR), strings are immutable, which means that once they have been created they cannot be changed. If you concatenate the two strings, str1 and str2, shown in the following code fragment, the resulting value of str1 is “1234567890”.

               Discussion
  str1 = "12345"
  str2 = "67890"
  str1 = str1 & str2

Discussion
  str1 = "12345";
  str2 = "67890";
  str1 = str1 + str2;

The way in which this concatenation is accomplished may come as a bit of a surprise to you. Since str1 cannot be changed (it is immutable), it is actually disposed of and a new string str1 is created that contains the concatenation of str1 and str2. As you might expect, there is a lot of overhead associated with this operation.

The StringBuilder object provides a much faster method of concatenating strings. A StringBuilder object treats strings as an array of characters that can be altered without recreating the object. When a StringBuilder object is created, the CLR allocates a block of memory in which to store the string. As characters are added to a StringBuilder object, they are stored in the already available block of memory. If the additional characters will not fit within the current block, additional memory is allocated to store the new data.

The default capacity of a StringBuilder is 16 characters, but the number can be set to any value up to 2,147,483,647 characters, the maximum size of an integer type. If you know approximately how long the final string will be, you can improve performance further by setting the maximum size when the StringBuilder is created, which reduces the number of additional memory allocations that must be performed.

As Figure 16-1 shows, the performance difference between classic concatenation and concatenation using a StringBuilder object is dramatic. Classic concatenation averaged 1.0188 milliseconds per concatenation, while using a StringBuilder object averaged 0.0003 milliseconds per concatenation, which is nearly 3,000 times faster.

StringBuilder objects are not limited to concatenation: they also support inserting, removing, replacing, and appending formatted strings. The StringBuilder is a significant improvement over the classic manipulation of strings.

Tip

The question always arises as to when classic string manipulation or a StringBuilder should be used. Every application is different. However, if you are performing a simple concatenation of less than 5-10 strings outside of a loop (done only once), you should probably use classic string manipulation due to the overhead of creating a StringBuilder object. Anytime you are performing string manipulations within a loop or are combining many string fragments, a StringBuilder should be used. If you are not sure, set up a test similar to the one we use in our examples for this recipe and measure the two approaches yourself.

See Also

In the MSDN Library, search for “Use StringBuilder for Complex String Manipulation”

Example 16-4. Measuring string concatenation performance (.aspx)

<%@ Page Language="vb" AutoEventWireup="false" 
    Codebehind="CH16StringManipulationPerformanceVB.aspx.vb" 
    Inherits="ASPNetCookbook.VBExamples.CH16StringManipulationPerformanceVB" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <head>
    <title>String Concatenation Performance</title>
    <link rel="stylesheet" href="css/ASPNetCookbook.css">
  </head>
  <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0">
    <form id="frmStringPerformance" method="post" runat="server">
      <table width="100%" cellpadding="0" cellspacing="0" border="0">
        <tr>
          <td align="center">
            <img src="images/ASPNETCookbookHeading_blue.gif">
          </td>
        </tr>
        <tr>
          <td class="dividerLine">
            <img src="images/spacer.gif" height="6" border="0"></td>
        </tr>
      </table>
      <table width="90%" align="center" border="0">
        <tr>
          <td align="center">&nbsp;</td>
        </tr>
        <tr>
          <td align="center" class="PageHeading">
            Improving String Concatenation Performance (VB)
          </td>
        </tr>
        <tr>
          <td><img src="images/spacer.gif" height="10" border="0"></td>
        </tr>
        <tr>
          <td align="center">
            <table width="70%" align="center" border="0">
              <tr>
                <td>&nbsp;</td>
                <td align="center">Time Per Concatenation (mSec)</td>
              </tr>
              <tr>
                <td>Classic Concatentation</td>
                                  <td id="cellClassic" runat="server" align="center"></td>
              </tr>
              <tr>
                <td>Using StringBuilder</td>
                                  <td id="cellSB" runat="server" align="center"></td>
              </tr>
            </table>
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

Example 16-5. Measuring string concatenation performance code-behind (.vb)

Option Explicit On 
Option Strict On
'-----------------------------------------------------------------------------
'
'   Module Name: CH16StringManipulationPerformanceVB.aspx.vb
'
'   Description: This module provides the code behind for the 
'                CH16StringManipulationPerformanceVB.aspx page
'*****************************************************************************
Imports System
Imports System.Text

Namespace ASPNetCookbook.VBExamples
  Public Class CH16StringManipulationPerformanceVB
    Inherits System.Web.UI.Page

    'controls on the form
    Protected cellClassic As System.Web.UI.HtmlControls.HtmlTableCell
    Protected cellSB As System.Web.UI.HtmlControls.HtmlTableCell

    '*************************************************************************
    '
    '   ROUTINE: Page_Load
    '
    '   DESCRIPTION: This routine provides the event handler for the page load
    '                event.  It is responsible for initializing the controls 
    '                on the page.
    '-------------------------------------------------------------------------
    Private Sub Page_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) Handles MyBase.Load

      Const STRING_SECTION As String = "1234567890"

                        Dim testStr As String
                        Dim testStrBuilder As StringBuilder
                        Dim counter As Integer
                        Dim startTime As DateTime
                        Dim elapsedTime As TimeSpan
                        Dim loops As Integer

                        'measure the elapsed time for 10000 classic string concatenation
                        loops = 10000
                        startTime = DateTime.Now( )
                        testStr = ""
                        For counter = 1 To loops
                          testStr &= STRING_SECTION
                        Next

                        elapsedTime = DateTime.Now.Subtract(startTime)

                        'set the table cell value to the average time per concatenation 
                        'in milliseconds
                        cellClassic.InnerText = _
                          (elapsedTime.TotalMilliseconds / loops).ToString("0.0000")

                        'measure the elapsed time for 1,000,000 classic string concatenation
                        'NOTE: Many more loops were used to provide a measureable time period
                        loops = 1000000
                        startTime = DateTime.Now( )
                        testStrBuilder = New StringBuilder
                        For counter = 1 To loops
                          testStrBuilder.Append(STRING_SECTION)
                        Next

                        elapsedTime = DateTime.Now.Subtract(startTime)

                        'set the table cell value to the average time per concatenation 
                        'in milliseconds
                        cellSB.InnerText = _
                          (elapsedTime.TotalMilliseconds / loops).ToString("0.0000")
    End Sub  'Page_Load
  End Class  'CH16StringManipulationPerformanceVB
End Namespace

Example 16-6. Measuring string concatenation performance code-behind (.cs)

//----------------------------------------------------------------------------
//
//   Module Name: CH16StringManipulationPerformanceCS.aspx.cs
//
//   Description: This class provides the code behind for
//                CH16StringManipulationPerformanceCS.aspx
//
//****************************************************************************
using System;
using System.Text;

namespace ASPNetCookbook.CSExamples
{
  public class CH16StringManipulationPerformanceCS : System.Web.UI.Page
  {
    // controls on the form
    protected System.Web.UI.HtmlControls.HtmlTableCell cellClassic;
    protected System.Web.UI.HtmlControls.HtmlTableCell cellSB;

    //************************************************************************
    //
    //   ROUTINE: Page_Load
    //
    //   DESCRIPTION: This routine provides the event handler for the page 
    //                load event.  It is responsible for initializing the 
    //                controls on the page.
    //------------------------------------------------------------------------
    private void Page_Load(object sender, System.EventArgs e)
    {
      const string STRING_SECTION = "1234567890";

                        string testStr = null;
                        StringBuilder testStrBuilder = null;
                        DateTime startTime;
                        TimeSpan elapsedTime;
                        int counter;
                        int loops;

                        // measure the elapsed time for 10000 classic string concatenation
                        loops = 10000;
                        startTime = DateTime.Now;
                        testStr = "";
                        for (counter = 1; counter <= loops; counter++)
                        {
                          testStr += STRING_SECTION;
                        }

                        elapsedTime = DateTime.Now.Subtract(startTime);

                        // set the table cell value to the average time per concatenation 
                        // in milliseconds
                        cellClassic.InnerText =
                          (elapsedTime.TotalMilliseconds / loops).ToString("0.0000");

                        // measure the elapsed time for 1,000,000 classic string concatenation
                        // NOTE: Many more loops were used to provide a measureable time period
                        loops = 1000000;
                        startTime = DateTime.Now;
                        testStrBuilder = new StringBuilder( );
                        for (counter = 1; counter <= loops; counter++)
                        {
                          testStrBuilder.Append(STRING_SECTION);
                        }

                        elapsedTime = DateTime.Now.Subtract(startTime);

                        // set the table cell value to the average time per concatenation 
                        // in milliseconds
                        cellSB.InnerText = 
                          (elapsedTime.TotalMilliseconds / loops).ToString("0.0000");
    }  // Page_Load
  }  // CH16StringManipulationPerformanceCS
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset