首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 精準效能測量:Stopwatch 類別完整指南與微秒級計時實戰

     編輯:關於C#

軟體效能優化的前提是「可測量」。.NET Framework 2.0 引入的 System.Diagnostics.Stopwatch 類別,提供了比傳統 DateTime 高得多的精度(可達微秒/百萬分之一秒),是進行程式碼區塊執行時間測量的標準工具。本文詳細說明其用法、屬性選擇與常見誤區。

為什麼需要 Stopwatch?

  • 精度:DateTime.Now 精度約 10-15 毫秒;Stopwatch 利用硬體高效能計時器,精度可達 0.0001 毫秒(100 奈秒)。
  • 累積誤差放大:極短程序(如 0.001 毫秒)若被呼叫 100 萬次,總耗時達秒級,唯有高精度計時器才能捕捉。
  • API 直觀:模擬實體秒錶操作——Start()、Stop()、Reset()、Restart()。

核心成員速查表

成員類型說明
Start()方法開始/繼續計時
Stop()方法暫停計時
Reset()方法歸零並停止
Restart()方法歸零並立即開始(等同 Reset+Start)
ElapsedTimeSpan總經過時間,最高精度,適合格式化輸出
ElapsedMillisecondslong總毫秒數(整數),精度較低,適合較長區間
ElapsedTickslong原始計時器節拍數,需配合 Frequency 換算
Frequencystatic long每秒節拍數(唯讀),由硬體/OS 決定
IsRunningbool是否正在計時
StartNew()static 方法建立實例並立即開始(工廠模式)

實戰範例:測量 1 到 10,000,000 累加耗時

using System;
using System.Diagnostics;

namespace PerfDemo
{
    class Program
    {
        static void Main()
        {
            var sw = Stopwatch.StartNew(); // 建立並啟動
            long total = 0;
            for (int i = 1; i <= 10_000_000; i++)
                total += i;
            sw.Stop();

            // 1 Tick = 100 奈秒 = 0.1 微秒
            decimal microseconds = sw.Elapsed.Ticks / 10m;
            Console.WriteLine($"執行時間: {microseconds:F1} 微秒");
            Console.WriteLine($"等同: {sw.ElapsedMilliseconds} 毫秒");
            Console.WriteLine($"原始 Ticks: {sw.ElapsedTicks:N0} (Frequency={Stopwatch.Frequency:N0})");
        }
    }
}

關鍵屬性選擇指南

  • Elapsed (TimeSpan):首選。提供 TotalMilliseconds、TotalMicroseconds(.NET 6+)、Ticks 等豐富屬性,格式化輸出最靈活。
  • ElapsedMilliseconds:僅需整數毫秒、區間較長(> 10ms)時使用,避免 TimeSpan 物件分配開銷。
  • ElapsedTicks:極度追求效能、自行換算、或需跨平台統一單位時使用。換算公式:秒數 = ElapsedTicks / (double)Frequency。

常見陷阱與最佳實踐

  1. 預熱:首次呼叫 JIT 編譯會額外耗時,正式測量前先跑幾輪預熱。
  2. 多次取平均:單次測量受 OS 調度干擾大,建議執行 10-100 次取中位數。
  3. 避免 Debug 模式:Debug 編譯禁用優化、插入檢查碼,結果失真。務必用 Release 模式且無偵錯器附加執行。
  4. 防止編譯器優化移除代碼:測量空循環或結果未使用的代碼可能被編譯器刪除。務必使用結果(如上例輸出 total)或標記變量 volatile。
  5. GC 干擾:長區間測量前呼叫 GC.Collect()、GC.WaitForPendingFinalizers()、再 GC.Collect(),減少測量中觸發 GC 的機率。

進階:自訂高精度計時輔助類

public static class Benchmark
{
    public static double Time(Action action, int iterations = 100)
    {
        // 預熱
        for (int i = 0; i < 5; i++) action();
        
        var sw = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++) action();
        sw.Stop();
        
        return sw.Elapsed.TotalMilliseconds / iterations; // 平均毫秒
    }
}

// 使用
double avgMs = Benchmark.Time(() => {
    // 待測代碼
}, 1000);
Console.WriteLine($"平均耗時: {avgMs:F4} ms");

總結

Stopwatch 是 .NET 開發者進行微基準測試的基石工具。掌握其精度來源、屬性選擇、預熱與多次取樣等技巧,能讓效能分析從「感覺慢」進化為「數據驅動的優化」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved