Improve string processing performance in ASP applications
James Mussondeveloper Services, Microsoft UK March 2003 Suitable for: Microsoft® Active Server Pages® Microsoft Visual Basic® Summary: Most Active Server Pages (ASP) applications must create HTML format presented to users through string connections. data. This paper compares several methods of creating this HTML data stream. In certain circumstances, certain methods are superior to other methods. This article assumes that you have a certain knowledge in ASP and Visual Basic programming. table of Contents
Introduction ASP Design String Connection Solution StringBuilder Built-in Method Test Results Summary Introduction When the ASP page is written, the developer is actually a formatted text stream that is written to the Web client through the response object provided by the ASP. There are many ways to create this text stream, and your choice will have a great impact on the performance and scalability of the web application. Many times, when I help customers optimize their web applications, find that one of the more effective ways is to change the creation of HTML streams. This article will introduce several common technologies and test their influence on a simple ASP page performance. ASP design Many ASP developers have followed the principles of software engineering and modularize their code as much as possible. This design typically uses some of the included files that contain a function of formatting a specific discontinuous part of the page. String output of these functions (usually HTML table code) can create a complete page through a variety of combinations. Some developers have improved this method, move these HTML functions to the Visual Basic COM component, and want to make full use of additional performance provided by the compiled code. Although this design method is very good, it is a great impact on the performance and scalability of these non-continuous HTML code components that have a great impact on the performance and scalability of the Web site, regardless of the actual operation is in the ASP containing files. Execute or execute in the Visual Basic COM component. String Connection See the code snippet of the following Writehtml function. The parameters named DATA are just a string array, which contains some data to format the table structure (for example, data returned from the database). Function Writehtml (DATA)
DIM NREP
For nrep = 0 to 99
SHTML = SHTML & VBCRLF _
& "
& Data (0, NREP) & " TD>
& Data (1, NREP) & " TD>
& Data (2, NREP) & " TD>
& Data (3, NREP) & " TD>
& Data (4, NREP) & " TD>
& Data (5, NREP) & " TD> TR>"
NEXT
Writehtml = SHTML
END FUNCTION
This is a method for many ASPs and Visual Basic developers to create HTML code. The text included in the SHTML variable returns to the calling code and then writes to the client using Response.write. Of course, this can also be represented as a similar code that is directly embedded from a page that does not contain a Writehtml function. The problem with this code is that the string data type (BSTR or BASIC string) used by the ASP and Visual Basic is actually unable to change. This means that whenever the string length changes, the original representation of the strings in the memory will be destroyed, and a new representation containing new string data will be created: this will increase the allocation of memory and release memory. operating. Of course, ASP and Visual Basic have solved this problem for you, so actual overhead will not appear immediately. Assigning Memory and Unpacking Memory Requirements Basic Runtime Codes Unpacking Each dedicated lock, therefore requires a lot of overhead. This problem becomes particularly pronounced when the string becomes large and there is a large block memory to be distributed and unassigned quickly, just like the case in a large string connection. Although this problem has little impact on the single user environment, in the server environment (for example, an ASP application running on the web server), it will lead to serious performance and scalability. Below, we return to the above code snippet: How many string allocation operations are to be executed in this code? The answer is 16. In this case, each application of the "&" operator will cause the string of variable SHTML to be destroyed and recreated. As mentioned earlier, the overhead of string allocation is large, and as the string increases, we can improve the above code. The short solution has two ways to alleviate the influence of string connections. The first method is to try to reduce the size of the string to be processed, and the second method is to try to reduce the number of string allocation operations. See the revision of the Writehtml code shown below. Function Writehtml (DATA) DIM NREP
For nrep = 0 to 99
SHTML = SHTML & (VBCRLF _
& "
& Data (0, NREP) & " TD>
& Data (1, NREP) & " TD>
& Data (2, NREP) & " TD>
& Data (3, NREP) & " TD>
& Data (4, NREP) & " TD>
& Data (5, NREP) & " TD> TR>")
NEXT
Writehtml = SHTML
END FUNCTION
At first glance, it may be difficult to find the difference between this code and the previous code example. In fact, this code is just in the content of SHTML = SHTML & and then the brackets are added. This is actually to reduce the string size processed in most string connection operations by changing the priority order. In the initial code example, the ASP compiler will view the expression on the right side of the equal sign and calculate from left to right. As a result, 16 connection operations are performed each time, which are performed for growing SHTML. In the new version, we prompt the compiler to change the order of operation. Now, it calculates the expression from left to right, order from the brackets to parentheses. This technique enables each repeating to include 15 connection operations, these operations are for a smaller string that does not grow, only one is for growing large SHTMLs. Figure 1 shows the comparison of this optimization method and standard connection method in memory usage mode. Figure 1: Comparison of standard connections and plug-in connections in memory usage mode, using parentheses can have a significant effect on performance and scalability, and will be further described later. StringBuilder We have found shortcuts for resolving string connection issues, in most cases, this method can achieve the best balance of performance and investment. However, if it is necessary to further improve the performance of building large strings, the second method needs to be used, that is, reduce the number of string allocation operations. To this end, StringBuilder needs to be used. StringBuilder is a class that maintains a new text snap that is inserted into this buffer inserted into this buffer, and reassigns the string only when the text length exceeds the string buffer length. The Microsoft .NET Framework provides such a class (System.Text.StringBuilder) and is recommended to use it in all string connection operations in this environment. In ASP and traditional Visual Basic environments, we cannot access such classes, so you need to create it yourself. Below is an example of StringBuilder class created using Visual Basic 6.0 (for simple origin, omitting error handling code). Option Explicit 'Default Buffer Initial Size and Growth Coefficient
Private const def_initialsize as long = 1000
PRIVATE CONST Def_GRowth as long = 1000
'Buffer size and growth
Private m_ninitialsize as long
PRIVATE M_NGROWTH AS Long
'Buffer and buffer counters
Private M_SText As String
PRIVATE M_NSIZE AS Long
Private m_npos as long
Private sub coplass_initialize ()
'Set the default value of size and growth
m_ninitialsize = def_initialsize
m_ngrowth = def_growth
'Initialization buffer
Initbuffer
End Sub
'Set the initial size and growth
Public Sub Init (Byval InitialSize As Long, Byval Growth As Long)
IF InitialSize> 0 Then m_ninitialsize = initialsize
IF Growth> 0 Then M_NGROWTH = Growth
End Sub
'Initialization buffer
Private subinitbuffer ()
m_nsize = -1
m_npos = 1
End Sub
'Increase Buffer Private Sub Grow (Optional MinimimGRowth As Long)
'Initialization buffer (if necessary)
IF m_nsize = -1 Then
m_nsize = m_ninitialsize
m_Stext = Space $ (m_ninitialsize)
Else
'Just grow
DIM NGROWTH AS Long
Ngrowth = IIF (M_NGROWTH> MinimimGRowth,
M_NGROWTH, MINIMIMIMGROWTH)
m_nsize = m_nsize ngrowth
m_stext = m_stext & space $ (ngrowth)
END IF
End Sub
'Adjust the buffer size to the current size
Private sub shrink ()
IF m_nsize> m_npos dam
m_nsize = m_npos - 1
m_stext = r r (m_stext)
END IF
End Sub
'Add a single text string
Private sub appendinternal (Byval Text As String)
IF (M_NPOS LEN (Text))> M_NSIZE THENGROW LEN (Text)
MID $ (m_stext, m_npos, len (text) = text
m_npos = m_npos len (text)
End Sub
'Add some text string
Public Sub append (paramarray text ())
DIM NARG As Long
For Narg = 0 to Ubound (Text)
Appendinternal CSTR (Text (NARG))
Next Narg
End Sub
'Return to the current string data and adjust the buffer size
Public function toString () AS STRING
IF m_npos> 0 THEN
Shrink
Tostring = m_stext
Else
Tostring = ""
END IF
END FUNCTION
'Clear the buffer and reinitialize
Public Sub Clear ()
Initbuffer
End Sub
The basic principle used in this class is to use the Space $ function to fill this buffer with a spacemill character with a space-mounted size in a class level. If you want to connect more text with existing text, use the MID $ function to insert the text in the correct location after the size of the buffer is insufficient enough to store new text. The toString function returns the text currently stored in the buffer and adjusts the size of the buffer to accommodate the correct length of this text. The ASP code using StringBuilder is as follows: Function Writehtml (DATA)
DIM OSB
DIM NREP
Set OSB = Server.createObject ("StringBuildervb.StringBuilder")
'Initializing buffers with size and growth coefficient
Osb.init 15000, 7500
For nrep = 0 to 99
Osb.append "
DATA (0, nrep), " td>
Data (2, nrep), " td>
Data (3, nrep), " td>
Data (4, nrep), " td>
DATA (5, nrep), " td> tr>"
NEXT
Writehtml = osb.tostring ()
Set OSB = Nothing
END FUNCTION
Using StringBuilder requires a certain overhead because each instance must be created each time you use this class, and you must load the DLL containing such a class when you create the first class instance. There is also a cost to turn on the StringBuilder instance. When using the "&" method of incarnation, StringBuilder performs how to be a number of factors, including the number of connections, the size of the string to build, and the performance of the initialization parameters of the selected StringBuilder string buffer. Note that in most cases, the amount of space required in the buffer is estimated is much better than growing. The built-in method ASP contains a very fast way to create an HTML code, just call RESPONSE.WRITE multiple times. The WRITE function uses implicit optimized string buffers that provide very good performance features. Modified Writehtml code as follows: Function Writehtml (DATA)
DIM NREP
For nrep = 0 to 99
Response.write "
Response.write (NREP 1)
Response.write " td>
Response.Write Data (0, NREP)
Response.write " td>
Response.Write Data (1, NREP)
Response.write " td>
Response.write Data (2, nrep)
Response.write " td>
Response.Write Data (3, NREP)
Response.write " td>
Response.Write Data (4, NREP)
Response.write " td>
Response.Write Data (5, nrep)
Response.write " td> tr>"
NEXT
END FUNCTION
Although this code is likely to provide us with optimal performance and scalability, it has already destroyed the package to some extent, because the code inside the function will now be written directly to the Response stream, so calling code lost a certain degree. Control. In addition, mobile this code (eg, moving into COM components) will become more difficult because this function is dependent on the RESPONSE flow. Test the four methods mentioned above with a simple ASP page (including a single table that provides data by the virtual string array). We use the Application Center Test® (ACT) from a single client (Windows® XP Professional, PIII-850MHz, 512MB RAM) to perform a single server in a 100MB / sec network (Windows 2000 Advanced Server, Dual PIII-1000MHz, 256MB RAM) Test. The ACT is configured to use 5 threads to simulate 5 users to connect to the website. Each test includes 20 seconds warm-up time and subsequent 100 second load time, created as many requests as possible during the load. Run the test by changing the number of repetitions in the primary table loop, and running tests for different number of connection operations, such as the code snippet in the WRITEHTML function. Each test run is performed using four different methods mentioned above. Results The following series of charts show various methods effects on the throughput of the entire application, as well as the response time of the ASP page. Through these charts, we can understand the number of requests supported by the application, and the time required for the user waiting page to download to the browser. Table 1: Description of connection methods used by connection method Abbreviation Description RESP Built-in Response.write Method CAT Standard Connection ("&") Method PCAT Package ("&") Method BLDRStringBuilder method In simulating typical ASP applications workload This test is far from the actual situation, it can be apparent from Table 2, even if it is repeated 420 times, this page is still not particularly large. Many complex ASP pages are now high on these numbers, and the settings may exceed this test range. Table 2: Test example page size and number of connections
Repeated number of connections Number of connections (in bytes) 152402, 667304804, 917457507, 167609609, 417751, 20011, 6671201, 92018, 5391802, 88027, 8992403, 84037, 2593004, 80046, 6193605, 76055, 9794206, 72062, 219 Figure 2: Throughput results diagram As can be seen from the chart of Figure 2, as we expect, multiple response.write methods provide us with the best throughput in the entire repeated test range of the test. But surprisingly, the standard string connection method (CAT) declines so huge, and the method of incarnation (PCAT) is still much better during repeated 300 times. In approximately 220 times, the performance of string caching has improved overhead inherent StringBuilder Method (BLDR), at this point, and the additional overhead required to use StringBuilder in this ASP page is worth it. Figure 3: Response time results Figure 4: omitting CAT response time results Figure 3 and Figure 4 show the response time (in milliseconds) measured by "to the first byte" measurement. Because the response time of the standard string connection method (CAT) increases too fast, there is also a chart that does not include this method (Figure 4) in order to analyze the differences between other methods. It is worth noting that multiple response.write methods (RESP) and STRINGBUILDER methods (BLDR) have an approximate linear growth with increased number of repetitions, while standard connection methods (CAT) and plug-in methods (PCAT) are exceeded A certain threshold begins to increase rapidly. Small junctions focused on how to apply different string build technologies in the ASP environment, which also apply to all scenarios using the Visual Basic code to create large strings, such as manually create an XML document. The following principles can help you determine which method is best for you. First, try the "&" method of parentheses, especially when dealing with existing code. This method has a minimal impact on the code structure, but you will find that the performance of the application will be significantly enhanced, and even a predetermined goal. Use Response.Write without destroying the required package level. Using this method, unnecessary internal string processing can be avoided to provide optimal performance. Use StringBuilder to build a string of true large or more connections. Although you may not see this performance growth shown in this article, I have used these techniques in a real ASP web application, just need little additional investment, you can get a lot in performance and scalability. Improvement.