如何使用C# Stopwatch 測量微秒級精確度
跟同事討論到- 用C# Stopwatch 取得效能數值,Stopwatch.ElapsedMilliseconds 隻到毫秒(ms),如果需要更高的時間精確度(微秒μs,甚至奈秒ns),該怎麼做?
原以為要費番功夫,在Stackoverlow查到討論,答案意外地簡單。
準備測試程式如下,比較MD5 及SHA1 計算1MB byte[] 雜湊值所秏費時間:
static byte[] data = new byte[1024 * 1024]; static void Main(string[] args) { Test1(); Console.ReadLine(); } private static void Test1() { Console.WriteLine("Test 1"); for (var i = 0; i < 5; i++) { Stopwatch sw = new Stopwatch(); sw.Start(); var md5 = MD5.Create().ComputeHash(data); sw.Stop(); Console.WriteLine($"MD5 {sw.ElapsedMilliseconds}ms"); sw.Restart(); var sha1 = SHA1.Create().ComputeHash(data); sw.Stop(); Console.WriteLine($"SHA1 {sw.ElapsedMilliseconds}ms"); } }
執行結果如下:
Test 1 MD5 10ms SHA1 2ms MD5 2ms SHA1 2ms MD5 2ms SHA1 2ms MD5 2ms SHA1 2ms MD5 2ms SHA1 2ms
有兩個問題,第一是回圈的第一次執行因涉及.NET 初始化,耗時會異常偏高(先做SHA1 再做MD5,就變成第一筆SHA1 超過10ms),第二是MD5 與SHA1 執行時間相近,都是2ms 多,用ElapsedMilliseconds 看不出差異。
針對首次數值耗時偏差問題,除瞭略過第一次數據不計,我想到的另一個解法是在Test1()前先跑一次MD5.Create()完成相關初始化。至於ElapsedMilliseconds看不出差異問題,改用ElapsedTicks是種解法,但要註意,ElaspedTicks換算成時間單位時,不是除以TimeSpan.TicksPerMillisecond而是依CPU頻率而定,需使用Stopwatch.Frequency (每秒Tick數)。
第二版改用ElapsedTicks * 1000000F / Stopwatch.Frequency 計算微秒(Microsecond, μs),執行前先MD5.Create() 暖機。
static byte[] data = new byte[1024 * 1024]; static void Main(string[] args) { MD5.Create(); Test2(); Console.ReadLine(); } private static void Test2() { Console.WriteLine("Test 2"); for (var i = 0; i < 5; i++) { Stopwatch sw = new Stopwatch(); sw.Start(); var md5 = MD5.Create().ComputeHash(data); sw.Stop(); // Console.WriteLine($"MD5 {sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs"); sw.Restart(); var sha1 = SHA1.Create().ComputeHash(data); sw.Stop(); Console.WriteLine($"SHA1 {sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs"); } }
執行結果的第一次時間偏長問題消失,而也呈現出SHA1 比MD5 計算耗時的證據。而由數值來看,精確度可到0.1μs = 100ns。
Test 2 MD5 2,402.200μs SHA1 2,724.000μs MD5 2,017.300μs SHA1 2,576.900μs MD5 2,102.100μs SHA1 2,578.700μs MD5 2,024.100μs SHA1 2,600.300μs MD5 2,008.300μs SHA1 2,624.300μs
自己計算麻煩瞭點,Stopwatch 有個Elapsed 屬性,型別為TimeSpan,其中TotalMilliseconds 屬性精確度即可達到μs 及100ns。請看第三版:
static byte[] data = new byte[1024 * 1024]; static void Main(string[] args) { MD5.Create(); Test3(); Console.ReadLine(); } private static void Test3() { Console.WriteLine("Test 3"); for (var i = 0; i < 5; i++) { Stopwatch sw = new Stopwatch(); sw.Start(); var md5 = MD5.Create().ComputeHash(data); sw.Stop(); Console.WriteLine($"MD5 {sw.Elapsed.TotalMilliseconds * 1000:n3}μs"); sw.Restart(); var sha1 = SHA1.Create().ComputeHash(data); sw.Stop(); Console.WriteLine($"SHA1 {sw.Elapsed.TotalMilliseconds * 1000:n3}μs"); } }
執行結果與第二版相同,但程式更簡單一些。
Test 3 MD5 2,423.400μs SHA1 2,692.400μs MD5 2,204.000μs SHA1 2,976.800μs MD5 2,094.500μs SHA1 2,588.600μs MD5 2,034.600μs SHA1 2,598.900μs MD5 2,029.900μs SHA1 2,887.000μs
以上就是如何使用C# Stopwatch 測量微秒精確度的詳細內容,更多關於C# Stopwatch 測量微秒精確度的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Java Stopwatch類,性能與時間計時器案例詳解
- c# 並行和多線程編程——認識Parallel
- C#使用Task實現並行編程
- C#使用async和await實現異步編程
- SQL Server批量插入數據案例詳解