首先,非常感謝趙老大的CodeTimer,它讓我們更好的了解到代碼執行的性能,從而可以讓我們從性能的角度來考慮問題,有些東西可能我們認為是這樣的,但經理測試并非如何,這正應了我之前的那名話:“機器最能證明一切”!
費話就不說了,看代碼吧:
1 /// <summary>2 /// 執行代碼規范3 /// </summary>4 public interface IAction5 {6 void Action();7 }8 9 /// <summary>10 /// 老趙的性能測試工具11 /// </summary>12 public static class CodeTimer13 {14 [DllImport("kernel32.dll", SetLastError = true)]15 static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime, out long lpExitTime, out long lpKernelTime, out long lpUserTime);16 17 [DllImport("kernel32.dll")]18 static extern IntPtr GetCurrentThread();19 public delegate void ActionDelegate();20 private static long GetCurrentThreadTimes()21 {22 long l;23 long kernelTime, userTimer;24 GetThreadTimes(GetCurrentThread(), out l, out l, out kernelTime, out userTimer);25 return kernelTime + userTimer;26 }27 static CodeTimer()28 {29 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;30 Thread.CurrentThread.Priority = ThreadPriority.Highest;31 }32 public static void Time(string name, int iteration, ActionDelegate action)33 {34 if (String.IsNullOrEmpty(name))35 {36 return;37 }38 if (action == null)39 {40 return;41 }42 43 //1. Print name44 ConsoleColor currentForeColor = Console.ForegroundColor;45 Console.ForegroundColor = ConsoleColor.Yellow;46 Console.WriteLine(name);47 48 // 2. Record the latest GC counts49 //GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);50 GC.Collect(GC.MaxGeneration);51 int[] gcCounts = new int[GC.MaxGeneration + 1];52 for (int i = 0; i <= GC.MaxGeneration; i++)53 {54 gcCounts[i] = GC.CollectionCount(i);55 }56 57 // 3. Run action58 Stopwatch watch = new Stopwatch();59 watch.Start();60 long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick61 for (int i = 0; i < iteration; i++) action();62 long ticks = GetCurrentThreadTimes() - ticksFst;63 watch.Stop();64 65 // 4. Print CPU66 Console.ForegroundColor = currentForeColor;67 Console.WriteLine("\tTime Elapsed:\t\t" +68 watch.ElapsedMilliseconds.ToString("N0") + "ms");69 Console.WriteLine("\tTime Elapsed (one time):" +70 (watch.ElapsedMilliseconds / iteration).ToString("N0") + "ms");71 Console.WriteLine("\tCPU time:\t\t" + (ticks * 100).ToString("N0")72 + "ns");73 Console.WriteLine("\tCPU time (one time):\t" + (ticks * 100 /74 iteration).ToString("N0") + "ns");75 76 // 5. Print GC77 for (int i = 0; i <= GC.MaxGeneration; i++)78 {79 int count = GC.CollectionCount(i) - gcCounts[i];80 Console.WriteLine("\tGen " + i + ": \t\t\t" + count);81 }82 Console.WriteLine();83 }84 85 86 87 public static void Time(string name, int iteration, IAction action)88 {89 if (String.IsNullOrEmpty(name))90 {91 return;92 }93 94 if (action == null)95 {96 return;97 }98 99 //1. Print name 100 ConsoleColor currentForeColor = Console.ForegroundColor; 101 Console.ForegroundColor = ConsoleColor.Yellow; 102 Console.WriteLine(name); 103 104 // 2. Record the latest GC counts 105 //GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 106 GC.Collect(GC.MaxGeneration); 107 int[] gcCounts = new int[GC.MaxGeneration + 1]; 108 for (int i = 0; i <= GC.MaxGeneration; i++) 109 { 110 gcCounts[i] = GC.CollectionCount(i); 111 } 112 113 // 3. Run action 114 Stopwatch watch = new Stopwatch(); 115 watch.Start(); 116 long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick 117 for (int i = 0; i < iteration; i++) action.Action(); 118 long ticks = GetCurrentThreadTimes() - ticksFst; 119 watch.Stop(); 120 121 // 4. Print CPU 122 Console.ForegroundColor = currentForeColor; 123 Console.WriteLine("\tTime Elapsed:\t\t" + 124 watch.ElapsedMilliseconds.ToString("N0") + "ms"); 125 Console.WriteLine("\tTime Elapsed (one time):" + 126 (watch.ElapsedMilliseconds / iteration).ToString("N0") + "ms"); 127 Console.WriteLine("\tCPU time:\t\t" + (ticks * 100).ToString("N0") 128 + "ns"); 129 Console.WriteLine("\tCPU time (one time):\t" + (ticks * 100 / 130 iteration).ToString("N0") + "ns"); 131 132 // 5. Print GC 133 for (int i = 0; i <= GC.MaxGeneration; i++) 134 { 135 int count = GC.CollectionCount(i) - gcCounts[i]; 136 Console.WriteLine("\tGen " + i + ": \t\t\t" + count); 137 } 138 Console.WriteLine(); 139 } 140 }
有了上面的codeTimer我們就來測試一個吧,如字條串和并的問題,用+=還是用StringBuilder呢,有點經驗的程序員肯定說是StringBuilder,是的,確實是后者,那我們就來看看這
兩種方法測試的結果吧
1 CodeTimer.Time("String Concat", 100000,2 () =>3 {4 var s = "1";5 for (int i = 1; i < 10; i++)6 s = s + "1";7 });8 9 CodeTimer.Time("StringBuilder Concat", 100000, 10 () => 11 { 12 var s = new StringBuilder(); 13 for (int i = 1; i < 10; i++) 14 s.Append("1"); 15 });
測試的結果如下:
從圖中我們可以看到StringBuilder快的很明顯,無論是執行時間,還是對CPU的消耗及GC回收都遠低于String的拼結,所以,才有以下結論: