[奧地利]Daniel Strigl 著 野比 譯
來源:http://www.codeproject.com
下載:
源檔案HighPerformanceTimerSource.zip
簡介
精確的時間計量方法在某些應用程式中是非常重要的。常用的 Windows API 方法 GetTickCount() 返回系統啟動後經過的毫秒數。另一方面,GetTickCount() 函數僅有 1ms 的分辨精度,很不精確。
故而,我們要另外尋找一種方法來精確測量時間。
Win32 API 使用 QueryPerformanceCounter() 和 QueryPerformanceFrequency() 方法支援高精度計時。這些方法,比“標準的”毫秒精度的計時方法如 GetTickCount() 之類有高得多的精度。另一方面來說,在 C# 中使用“非託管”的 API 函數會有一定的開銷,但比起使用一點都不精確的 GetTickCount() API 函數來說要好得多了。
第一個函數 QueryPerformanceCounter() 查詢任意時刻高精度計數器的實際值。第二個函數 QueryPerformanceFrequency() 返回高精度計數器每秒的計數值。為了獲得某一程式碼片段經曆的時間,你需要獲得程式碼片段開始前和結束後這兩個計時時刻的高精度計數器實際值。這兩個值的差指出了程式碼片段執行所經曆的時間。
然後通過將差除以每秒計數值(高精度計時器頻率),就可以計算經過的時間了。
duration = (stop - start) / frequency
經過時間 = (停止時間 - 開始時間) / 頻率
需要關於 QueryPerformanceCounter 和 QueryPerformanceFrequency 的更多資訊,請參閱 MSDN 文檔。
代碼
下面的類實現了 QueryPerformanceCounter() 和 QueryPerformanceFrequency() API 函數的功能。
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;
namespace Win32
{
internal class HiPerfTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(
out long lpFrequency);
private long startTime, stopTime;
private long freq;
// 建構函式
public HiPerfTimer()
{
startTime = 0;
stopTime = 0;
if (QueryPerformanceFrequency(out freq) == false)
{
// 不支援高效能計數器
throw new Win32Exception();
}
}
// 開始計時器
public void Start()
{
// 來讓等待線程工作
Thread.Sleep(0);
QueryPerformanceCounter(out startTime);
}
// 停止計時器
public void Stop()
{
QueryPerformanceCounter(out stopTime);
}
// 返回計時器經過時間(單位:秒)
public double Duration
{
get
{
return (double)(stopTime - startTime) / (double) freq;
}
}
}
}
使用這個類很簡單。只需要建立一個 HiPerfTimer 的執行個體,然後調用 Start() 開始計時,Stop() 停止計時。要獲得經過的時間,調用 Duration() 函數即可。
參考下面的例子。
HiPerfTimer pt = new HiPerfTimer(); // 建立新的 HiPerfTimer 對象
pt.Start(); // 啟動計時器
Console.WriteLine("Test\n"); // 需要計時的代碼
pt.Stop(); // 停止計時器
Console.WriteLine("Duration: {0} sec\n",
pt.Duration); // 列印需要計時部分代碼的用時
下面的圖片是該例子在我系統上的輸出。