将不确定变为确定~老赵写的CodeTimer是代码性能测试的利器

来源:互联网 发布:网络电影招商方案 编辑:程序博客网 时间:2024/05/21 17:49

首先,非常感谢赵老大的CodeTimer,它让我们更好的了解到代码执行的性能,从而可以让我们从性能的角度来考虑问题,有些东西可能我们认为是这样的,但经理测试并非如何,这正应了我之前的那名话:“机器最能证明一切”!

费话就不说了,看代码吧:

复制代码
  1     /// <summary>  2     /// 执行代码规范  3     /// </summary>  4     public interface IAction  5     {  6         void Action();  7     }  8   9     /// <summary> 10     /// 老赵的性能测试工具 11     /// </summary> 12     public static class CodeTimer 13     { 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 name 44             ConsoleColor currentForeColor = Console.ForegroundColor; 45             Console.ForegroundColor = ConsoleColor.Yellow; 46             Console.WriteLine(name); 47  48             // 2. Record the latest GC counts 49             //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 action 58             Stopwatch watch = new Stopwatch(); 59             watch.Start(); 60             long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick 61             for (int i = 0; i < iteration; i++) action(); 62             long ticks = GetCurrentThreadTimes() - ticksFst; 63             watch.Stop(); 64  65             // 4. Print CPU 66             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 GC 77             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 name100             ConsoleColor currentForeColor = Console.ForegroundColor;101             Console.ForegroundColor = ConsoleColor.Yellow;102             Console.WriteLine(name);103 104             // 2. Record the latest GC counts105             //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 action114             Stopwatch watch = new Stopwatch();115             watch.Start();116             long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick117             for (int i = 0; i < iteration; i++) action.Action();118             long ticks = GetCurrentThreadTimes() - ticksFst;119             watch.Stop();120 121             // 4. Print CPU122             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 GC133             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的拼结,所以,才有以下结论:

在字符串拼结时,请使用StringBuilder吧!