我們在開發的過程中,很多時候一個功能可能有多個實現方法,為了追求代碼的性能,我們往往需要比較各實現方法的運行時間,從而選擇性能最好的實現方法。那么怎樣計算一段代碼(或者說是函數)的運行時間呢,這個就是這篇文章我們要總結的內容。我們主要分以下幾點來總結。
在C#程序中要計算代碼段(或方法)的執行時間,我們一般都使用Stopwatch類,我比較了使用+=和使用StringBuilder分別拼接字符串的性能差異,示例代碼如下。
1 namespace Consoleapplication5 2 { 3 class PRogram 4 { 5 static void Main(string[] args) 6 { 7 // 初始化性能計數器 8 CodeTimer.Initialize(); 9 10 // 定義執行次數11 int iteration = 100 * 1000; //10萬次12 13 string s = string.Empty;14 CodeTimer.Time("String Concat", iteration, () => 15 {16 s += "a"; 17 });18 19 StringBuilder sb = new StringBuilder();20 CodeTimer.Time("StringBuilder", iteration, () => 21 {22 sb.Append("a"); 23 });24 25 Console.ReadKey();26 }27 }28 }
運行結果如下圖。

我這里使用了封裝的一個性能計時器,文章后面會附上源代碼。
sql server中一般使用GetDate和DateDiff函數來計算sql語句運行的時間,示例代碼如下。
1 USE PackageFHDB; 2 GO 3 4 -- 開始時間 5 DECLARE @t1 AS DATETIME; 6 SELECT @t1= GETDATE(); 7 8 -- 運行的sql語句 9 SELECT TOP 1000 * FROM dbo.Pkg_PkgOrderMaster;10 11 -- 打印結果12 PRINT DATEDIFF(millisecond,@t1,GETDATE());
執行結果為293毫秒,如下圖。

附:性能計時器的源代碼

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Diagnostics; 6 using System.Threading; 7 using LNFramework.Common.Extends; 8 using System.Runtime.InteropServices; 9 10 namespace LNFramework.Common.Tools11 {12 /// <summary>13 /// 性能計時器14 /// </summary>15 public static class CodeTimer16 {17 /// <summary>18 /// 初始化19 /// </summary>20 public static void Initialize()21 {22 // 將當前進程及線程的優先級設為最高,減少操作系統在調度上造成的干擾23 // 然后調用一次Time方法進行預熱,以便讓Time方法盡快進入狀態24 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;25 Thread.CurrentThread.Priority = ThreadPriority.Highest;26 Time("", 1, () => { });27 }28 29 /// <summary>30 /// 計時31 /// </summary>32 /// <param name="name">名稱</param>33 /// <param name="iteration">循環次數</param>34 /// <param name="action">方法體</param>35 public static void Time(string name, int iteration, Action action)36 {37 if (name.IsNullOrEmpty()) return;38 39 // 1.保留當前控制臺前景色,并使用黃色輸出名稱參數40 ConsoleColor currentForeColor = Console.ForegroundColor;41 Console.ForegroundColor = ConsoleColor.Yellow;42 Console.WriteLine(name);43 44 // 2.強制GC進行收集,并記錄目前各代已經收集的次數45 GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);46 int[] gcCounts = new int[GC.MaxGeneration + 1];47 for (int i = 0; i <= GC.MaxGeneration; i++)48 {49 gcCounts[i] = GC.CollectionCount(i);50 }51 52 // 3.執行代碼,記錄下消耗的時間及CPU時鐘周期53 Stopwatch watch = new Stopwatch();54 watch.Start();55 ulong cycleCount = GetCycleCount();56 for (int i = 0; i < iteration; i++)57 {58 action();59 }60 ulong cpuCycles = GetCycleCount() - cycleCount;61 watch.Stop();62 63 // 4.恢復控制臺默認前景色,并打印出消耗時間及CPU時鐘周期64 Console.ForegroundColor = currentForeColor;65 Console.WriteLine("/tTime Elapsed:/t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");66 Console.WriteLine("/tCPU Cycles:/t" + cpuCycles.ToString("N0"));67 68 // 5.打印執行過程中各代垃圾收集回收次數69 for (int i = 0; i <= GC.MaxGeneration; i++)70 {71 int count = GC.CollectionCount(i) - gcCounts[i];72 Console.WriteLine("/tGen " + i + ": /t/t" + count);73 }74 75 Console.WriteLine();76 }77 78 private static ulong GetCycleCount()79 {80 ulong cycleCount = 0;81 QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);82 return cycleCount;83 }84 85 [DllImport("kernel32.dll")]86 [return: MarshalAs(UnmanagedType.Bool)]87 static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);88 89 [DllImport("kernel32.dll")]90 static extern IntPtr GetCurrentThread();91 }92 }
參考文章:
一個簡單的性能計數器:CodeTimer
新聞熱點
疑難解答