String performance in a translated. Net

Source: Internet
Author: User
Tags foreach bool coding standards comparison execution garbage collection memory usage
Performance | strings

Introduction

The way you handle strings in your code can have a surprising effect on performance. In this article, I need to consider two problems that arise as a result of using strings: the use of temporary string variables and string concatenation.

Background

Every project has a time when you need to think about coding standards for it. Using FxCop is a good start. My favorite set of FXCOP rules is the "performance" group.

So, I used FxCop to check my project and found a series of string problems. I must confess one thing: I often encounter problems with the immutable (immutable) strings of C #. When I see Mystring.toupper (), I often forget that it is not changing the content of myString but returning a whole new string (this is because the strings in C # are immutable).

I made some corrections to the code to get rid of the FxCop warning, and then I found that the code was faster than before. I decided to start a survey and eventually I would write the code for those tests.

Using the Code

The code for the test is simple. A console program calls four test methods, each of which executes a string-processing routine 1000 times (the entire execution time is long enough to see the performance difference).

The four test methods were divided into two groups, two for each group. The first group compares two methods for string comparisons that are not case sensitive (case-insensitive).

String Comparison and temporary string creation

The first Test routine is a crappy case-insensitive string comparison. The code for the comparison routine is:

static bool Badcompare (string Stringa, String stringb)
{
Return (stringa.toupper () = = Stringb.toupper ());
}

For this piece of code, FXCOP the following recommendations:

"Stringcomparetest.badcompare (String, String): Boolean calls String.op_equality (String, String): Boolean after Converting ' stack1 ', a local, to upper or lowercase. If possible, eliminate the string creation and call the overload of String.Compare, performs a case-insensitive compar Ison. "

This proposal means that each call to the ToUpper () creates a temporary string that is created and managed by the garbage collector. This takes extra time and uses more memory. The String.Compare method is (relatively) more efficient.

The second Test routine uses String.Compare:

static bool Goodcompare (string Stringa, String stringb)
{
Return (String.Compare (Stringa, STRINGB, true, System.Globalization.CultureInfo.CurrentCulture) = = 0);
}

This method prevents the creation of extra temporary strings.

According to Nprof's analysis, Goodcompare's execution time accounted for only 1.69% of the total code execution time, while Badcompare execution time accounted for 5.5% of the total execution time.

So the String.Compare method is three times times faster than the ToUpper method. If your code performs a lot of string comparisons (especially in loops), use String.Compare to improve your code's performance.

String concatenation inside a loop

Finally, the connection to the test routines assumption string is carried out in a loop.

The code for the "crappy" test routine is as follows:

static string Badconcatenate (string [] items)
{
String strret = String. Empty;

foreach (string item in items)
{
Strret + = Item;
}

return strret;
}

When FxCop sees this code, it gets angry and even signs the broken rule in red! FxCop said:

"Change Stringcomparetest.badconcatenate (string[]): String to use StringBuilder instead of string.concat or ="

The code for the "good" test routine is as follows:

static string Goodconcatenate (string [] items)
{
System.Text.StringBuilder builder = new System.Text.StringBuilder ();

foreach (string item in items)
{
Builder. Append (item);
}

Return builder. ToString ();
}

This code is almost used as a preferred example for showing the usage of System.Text.StringBuilder. The problem with crappy code is that it creates too many temporary strings. Because of the immutable character of the string, the concatenation operator (+ =) actually creates a new string with the original two strings, and then points the original string instance to the new string.

However, based on NPROF to study the performance of the code, we found that running badconcatenate only 5.67% of the total execution time, and Goodconcatenate is 22.09%. Other words:

The time spent using StringBuilder is almost four times times that of a simple string connection!

Why, then?

This is partly due to the design of the test-the connection routines connect only 10 short strings. StringBuilder is a more complex class than a simple immutable string class, so creating a StringBuilder is a much more expensive performance than making 10 simple string connections.

I repeated the tests for different numbers of string connections and found the following results:

Note: The value shown here is the percentage (%) of the total execution time of the test routine. Goodconcatenate is not actually much faster, but it is relatively fast compared to badconcatenate.

Therefore, StringBuilder usually shows a real performance advantage only if the number of strings you are connecting to is more than 600.

Of course, another reason to use StringBuilder is the allocation of memory. Use Clrprofiler to generate the following sequence diagram of memory usage when connecting 100 simple strings:

Areas labeled "A" show the effect of badconcatenate on memory allocation and release. The maximum value of the allocated memory is rapidly increasing, with a large number of garbage collections occurring (approximately 215 garbage collections in the area).

The area immediately following the "A" area shows the goodconcatenate memory outline. The maximum number of allocated memory increments is less and accompanies a very small amount of garbage collection (the area has roughly 60 garbage collections).

So in some cases using the StringBuilder class does not (make your code run faster), but it is friendly to the garbage collector.

Conclusions

Use the String.Compare method for case-insensitive string comparisons. So much quicker. And the code is elegant and simple.

Use StringBuilder to get better speed only when you have more than 600 string connections in a loop. The caveat here is that the length of the string you are dealing with will also affect the final speed, which will also affect the garbage collector's effect, so you should specifically analyze the problem based on your actual code.

Points of Interest

To my surprise, it's still very different in the real world to use the right code string manipulation (although we've done a lot of string comparisons and connections in the current project).

FxCop's performance rules are a good starting point for discovering potentially low performance code and can guide you through some simple fixes to improve code performance. The two issues discussed here are labeled "non-breaking" by FxCop, which means that changes should not break code that relies on altered code. The idea that changes made to improve performance are "non-breaking" is mindless.

Further considerations by Allen Lee

The connection that uses StringBuilder to handle strings should be the consensus of most. NET developers. But have you ever doubted that the applicability of this principle of experience is as broad as it is supposed to be? After reading this article, you may have realized that this is a moderate problem. The improvement in the use of StringBuilder for small string concatenation is simply not sufficient to compensate for the overhead of the complexity of the StringBuilder itself; only when the scale of the connection reaches a critical scale can the two compensate each other and achieve balance.

For actual code, a critical size value that can be used may be required, especially on a restricted system. You may be skeptical of the numbers given by the author because you have an understanding of the factors that affect the critical scale. Perhaps the design that this article uses for testing is a little too simple to convince more people, but you do know from this article that StringBuilder is not always applicable. Because the factors that affect the critical scale are always likely to change, you cannot find a critical size value that is applicable to any situation. You should tailor one to your code and be ready to adjust (because change always exists) as long as you really care about the performance impact. As a starting point, you can use the number that the author mentions in this article as a reference base and fine-tune the situation until you are satisfied.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.