現代 CPU 多核心、超標量架構、快取與指令管線導致同一程式碼執行時間波動高達 25-30%。本文介紹如何配置 System.Diagnostics.Stopwatch 達到 0.1-0.2% 測量精度,使演算法比較具備統計意義。
| 干擾源 | 對策 | 代碼 |
|---|---|---|
| CPU 核心切換 | 鎖定處理器親和性 | Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); // 僅使用第 2 核心 |
| 其他執行緒/進程搶佔 | 提升進程與執行緒優先權 | Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; |
| 冷啟動效應(JIT、快取預熱) | 執行暖機迴圈至穩定 | 見下方完整範例 |
| JIT 優化移除無用運算 | 保留運算結果並最終輸出 | result ^= TestFunction(...); Console.WriteLine(result); |
using System;
using System.Diagnostics;
using System.Threading;
namespace PreciseMeasure {
class Program {
static void Main(string[] args) {
Stopwatch sw = new Stopwatch();
long seed = Environment.TickCount;
long result = 0;
int count = 100_000_000;
Console.WriteLine("20 Tests WITHOUT correct preparation");
for (int i = 0; i < 20; ++i) {
sw.Reset(); sw.Start();
result ^= TestFunction(seed, count);
sw.Stop();
Console.WriteLine($"Ticks: {sw.ElapsedTicks} mS: {sw.ElapsedMilliseconds}");
}
// === 正確配置 ===
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Console.WriteLine("\n20 Tests WITH correct preparation");
Console.WriteLine("Warmup...");
sw.Reset(); sw.Start();
while (sw.ElapsedMilliseconds < 1200) { // 1.2 秒暖機
result = TestFunction(seed, count);
}
sw.Stop();
for (int i = 0; i < 20; ++i) {
sw.Reset(); sw.Start();
result ^= TestFunction(seed, count);
sw.Stop();
Console.WriteLine($"Ticks: {sw.ElapsedTicks} mS: {sw.ElapsedMilliseconds}");
}
Console.WriteLine(result); // 防止編譯器優化移除
}
public static long TestFunction(long seed, int count) {
long result = seed;
for (int i = 0; i < count; ++i)
result ^= i ^ seed; // 簡單位運算負載
return result;
}
}
}
Ticks: 1580367 mS: 572 <-- 最高
Ticks: 1577003 mS: 571
...
Ticks: 1112012 mS: 402 <-- 最低
...
Ticks: 1349507 mS: 488
執行時間分佈 **402ms ~ 572ms**,差距 **170ms (42%)**,無法用於比較。
Ticks: 1110518 mS: 402
Ticks: 1110540 mS: 402
...
Ticks: 1110684 mS: 402 <-- 最高
...
Ticks: 1110433 mS: 402 <-- 最低
20 次測試皆為 **402ms**,僅 **Tick 差異 251 (0.02%)**,對應 **0.09ms** 差異,極適合演算法基準測試。
未配置的「最好成績」仍比配置後的「最差成績」慢。
CPU 上下文切換與核心遷移對效能影響極大,嚴格的測試環境控制是精準測量的前提。
參考英文原文:Stopwatch Measure Precise