简介
精确的时间计量方法在某些应用程序中是非常重要的。常用的 Windows API 方法 GetTickCount() 返回系统启动后经过的毫秒数。另一方面,GetTickCount() 函数仅有 1ms 的分辨精度,很不精确。
故而,我们要另外寻找一种方法来精确测量时间。
Win32 API 使用 QueryPerformanceCounter() 和 QueryPerformanceFrequency() 方法支持高精度计时。这些方法,比“标准的”毫秒精度的计时方法如 GetTickCount() 之类有高得多的精度。另一方面来说,在 C# 中使用“非托管”的 API 函数会有一定的开销,但比起使用一点都不精确的 GetTickCount() API 函数来说要好得多了。
第一个函数 QueryPerformanceCounter() 查询任意时刻高精度计数器的实际值。第二个函数 QueryPerformanceFrequency() 返回高精度计数器每秒的计数值。为了获得某一代码段经历的时间,你需要获得代码段开始前和结束后这两个计时时刻的高精度计数器实际值。这两个值的差指出了代码段执行所经历的时间。
然后通过将差除以每秒计数值(高精度计时器频率),就可以计算经过的时间了。
duration = (stop - start) / frequency
经过时间 = (停止时间 - 开始时间) / 频率
下面的类实现了 QueryPerformanceCounter() 和 QueryPerformanceFrequency() API 函数的功能。
public class HiperTimer { [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 readonly long _frequency; // 构造函数 public HiperTimer() { _startTime = 0; _stopTime = 0; if (QueryPerformanceFrequency(out _frequency) == false) {// 不支持高性能计数器 throw new Win32Exception(); } } // 开始计时器 public void Start() { // 来让等待线程工作 Thread.Sleep(0); QueryPerformanceCounter(out _startTime); } // 停止计时器 public void Stop() { QueryPerformanceCounter(out _stopTime); } // 返回计时器经过时间(单位:秒) public double EliminatedSecond { get { return (_stopTime - _startTime) / (double) _frequency; } } public double EliminatedMilliSecond { get { return (double) (_stopTime - _startTime)*1000/_frequency; } } public double EliminatedMicroSecond { get { return (double)(_stopTime - _startTime) * 1000000 / _frequency; } } }
使用过程如下:
private static void Main(string[] args) { var pt = new HiperTimer(); pt.Start(); // 启动计时器 Console.WriteLine("Test the time. "); // 需要计时的代码 pt.Stop(); // 停止计时器 Console.WriteLine("Duration: {0} sec",pt.EliminatedSecond); Console.WriteLine("Duration: {0} ms", pt.EliminatedMilliSecond); Console.WriteLine("Duration: {0} us", pt.EliminatedMicroSecond); }
运行结果: