您的位置:首页 > 编程语言

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

2018-01-18 12:49 274 查看
首先,非常感谢赵老大的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 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的拼结,所以,才有以下结论:

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: