A few days ago, N articles were published saying that c#/.net is too slow and demanding that some features of c#/.net be deleted.
Regardless of those articles, it seems to be an ironclad rule recognized by the industry that c#/.net is slow. No matter how everyone proves that c#/.net is not much slower than c++, the application-level performance is still so slow.
So where is c#/.net slow?
Unfortunately, most C# programs are slowed down by most programmers. This conclusion may not be easy to accept, but it is widespread.
String operations
Almost all programs have String operations, and at least 90% of them need to ignore case comparisons. Check the code. At least half of them have code similar to this:
if (str1.ToUpper() == str2.ToUpper())
Or the ToLower version, I even saw that there is a Web HttpModule that says:
for (int i = 0; i < strs.Count; i++)
if (value.ToUpper() == strs[i].ToUpper())
//...
Think about it, every time a page is requested, such a piece of code must be executed to create string instances in large tracts. What is even more exaggerated is that some people say that this is exchanging space for time. . .
Performance testing
If this method is said to be slow, some people may not admit it and think this is the best method, so here we need to use specific tests to prove the fact.
First prepare a method to test performance:
private static TResult MeasurePerformance<TArg, TResult>(Func<TArg, TResult> func, TArg arg, int loop)
{
GC.Collect();
int gc0 = GC.CollectionCount(0);
int gc1 = GC.CollectionCount(1);
int gc2 = GC.CollectionCount(2);
TResult result = default(TResult);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < loop; i++)
{
result = func(arg);
}
Console.WriteLine(sw.ElapsedMilliseconds.ToString() + "ms");
Console.WriteLine("GC 0:" + (GC.CollectionCount(0) - gc0).ToString());
Console.WriteLine("GC 1:" + (GC.CollectionCount(1) - gc1).ToString());
Console.WriteLine("GC 2:" + (GC.CollectionCount(2) - gc2).ToString());
return result;
}
Then prepare a heap string:
private static List<string> CreateStrings()
{
List<string> strs = new List<string>(10000);
char[] chs = new char[3];
for (int i = 0; i < 10000; i++)
{
int j = i;
for (int k = 0; k < chs.Length; k++)
{
chs[k] = (char)('a' + j % 26);
j = j / 26;
}
strs.Add(new string(chs));
}
return strs;
}
Then let’s take a look at the implementation of ToUpper:
private static bool ImplementByToUpper(List<string> strs, string value)
{
for (int i = 0; i < strs.Count; i++)
if (value.ToUpper() == strs[i].ToUpper())
return true;
return false;
}
Finally prepare the main method:
List<string> strs = CreateStrings();
bool result;
Console.WriteLine("Use ImplementByToUpper");
result = MeasurePerformance(s => ImplementByToUpper(strs, s), "yZh", 1000);
Console.WriteLine("result is " + result.ToString());
Console.ReadLine();
Let’s take a look at the execution results:
Use ImplementByToUpper
2192ms
GC 0:247
GC 1:0
GC 2:0
result is True
Let’s do a comparative test and use string.Equals to test:
private static bool ImplementByStringEquals(List<string> strs, string value)
{
for (int i = 0; i < strs.Count; i++)
if (string.Equals(value, strs[i], StringComparison.CurrentCultureIgnoreCase))
return true;
return false;
}
Let’s take a look at the execution results:
Use ImplementByStringEquals
1117ms
GC 0:0
GC 1:0
GC 2:0
result is True
In comparison, using ToUpper is twice as slow and has a lot of generation 0 garbage objects. Those who claim to trade space for time can reflect on this. What did they get in exchange for space? Negative time?
Use of dictionary class
Continuing with the string scenario, some people may think of using Hash tables and other similar structures to speed up. Yes, this is a good idea, but Hash tables are not always the best solution. Why don't you believe it? Let’s do a test:
private static bool ImplementByHashSet(List<string> strs, string value)
{
HashSet<string> set = new HashSet<string>(strs, StringComparer.CurrentCultureIgnoreCase);
return set.Contains(value);
}
Take a look at the execution results:
Use ImplementByHashSet
5114ms
GC 0:38
GC 1:38
GC 2:38
result is True
Surprisingly, the speed is more than twice as slow as using ToUpper, and the second-generation garbage is also collected 38 times (when executing the second-generation garbage collection, the first-generation and zero-generation garbage collection will be forced).
However, the idea of using a Hash table or the like to speed up the process is a very correct idea, but the premise is that the Hash table itself can be cached, for example:
private static Func<string, bool> ImplementByHashSet2(List<string> strs)
{
HashSet<string> set = new HashSet<string>(strs, StringComparer.CurrentCultureIgnoreCase);
return set.Contains;
}
Then modify the main method to:
Console.WriteLine("Use ImplementByHashSet2");
result = MeasurePerformance(s =>
{
var f = ImplementByHashSet2(strs);
bool ret = false;
for (int i = 0; i < 1000; i++)
{
ret = f(s);
}
return ret;
}, "yZh", 1);
Console.WriteLine("result is " + result.ToString());
Console.ReadLine();
Let’s take a look at the results:
Use ImplementByHashSet2
6ms
GC 0:0
GC 1:0
GC 2:0
result is True
Performance has increased dramatically.
More
What slows down c#/.net? To put it simply: unnecessary creation of objects, unnecessary synchronization, inefficient methods of loop execution (such as reflection that was criticized by firelong, but ms does not let you use Invoke in the loop), use of inefficient data structures and Algorithm (look at the amazing performance of a similar structure of the Hash table in the case of caching, and you will know the difference)
The low threshold of c#/.net does help attract more programmers to c#/.net to a certain extent, but it also reduces the code level of the entire c#/.net program a lot, which is really impressive. People worry.
Finally, don't forget that the performance of a system is not determined by the best-performing part of the system, but by the worst-performing part of the system. Equipped with a 16g memory, 100t hard drive, plus a top-notch graphics card, but without a 386 CPU, the performance of this computer is the performance of the 386. Similarly, no matter how good C#/.net is, if the skill of the programmer is poor, the performance of the written program will naturally be poor.