在效能分析與高效能伺服器開發中,常見需求是統計「每秒處理多少封包」。直覺公式是 總處理封包數 / 總耗時,但這裡的「耗時」若混淆了 實際經過時間 與 CPU 佔用時間,結論可能會誤導優化方向。
| 指標 | 取得方式 | 意義 |
|---|---|---|
| 實際經過時間 | Stopwatch.Elapsed | 從開始到結束的牆鐘時間,包含等待、I/O、排程切換 |
| CPU 時間 | Process.GetCurrentProcess().TotalProcessorTime | 執行緒真正佔用 CPU 運算的總和,不含等待時間 |
private void ShowRunTime()
{
// 取得起始 CPU 時間
TimeSpan cpuStart = Process.GetCurrentProcess().TotalProcessorTime;
// 實際時間用 Stopwatch
Stopwatch sw = Stopwatch.StartNew();
int circles = 1000;
for (int i = 0; i < circles; ++i)
{
Console.WriteLine(i.ToString()); // 包含 I/O 等待
}
sw.Stop();
// 計算 CPU 時間差
double cpuMs = Process.GetCurrentProcess().TotalProcessorTime.Subtract(cpuStart).TotalMilliseconds;
Console.WriteLine($"迴圈次數:{circles} CPU時間(ms)={cpuMs:F3} 實際時間(ms)={sw.Elapsed.TotalMilliseconds:F3}");
Console.WriteLine($"1 tick = {sw.Elapsed.TotalMilliseconds / sw.Elapsed.Ticks:F6} 毫秒");
}
迴圈次數:1000 CPU時間(ms)=50.072 實際時間(ms)=666.907
1 tick = 0.000100 毫秒
兩者相差 13 倍!主因有二:
Console.WriteLine 內部涉及非同步 I/O,呼叫執行緒在等待完成期間不佔用 CPU,但實際時間持續流逝。Stopwatch 精度達 0.1 微秒(視硬體而定),足夠應付大多數微基準測試。理解「牆鐘時間」與「CPU 時間」的定義差異,能避免在效能分析時誤判瓶頸位置,進而採取正確的優化策略。