在 C#開發(fā)過程中,經(jīng)常需要用到定時器,如果只是為了開啟一個線程,或者異步的做一些事情倒還好,直接使用 Form 或者 Thread 的 Timer 功能即可。
但是如果需求是比較精確的計時功能,這個 Timer 就極不好用了,因為他們是線程上的定時器,會受到系統(tǒng)調度的干擾,精度非常差,CPU 使用率高一點點就會影響計時精度。
常用的 Windows API 方法 GetTickCount() 返回系統(tǒng)啟動后經(jīng)過的毫秒數(shù)。另一方面,GetTickCount() 函數(shù)僅有 1ms 的分辨精度,精度也很不好。
我們要另外尋找一種方法來精確測量時間。
Win32 API 使用 QueryPerformanceCounter() 和 QueryPerformanceFrequency() 方法支持高精度計時。這些方法,比“標準的”毫秒精度的計時方法如 GetTickCount() 之類有高得多的精度。
雖然在 C# 中使用“非托管”的 API 函數(shù)會有一定的開銷,但比起使用一點都不精確的 GetTickCount() API 函數(shù)來說要好得多了。
下面的類實現(xiàn)了 QueryPerformanceCounter() 和 QueryPerformanceFrequency() API 函數(shù)功能的封裝。
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;
namespace Win32
{
internal class HighTimer
{
[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;
// 構造函數(shù)
public HighTimer()
{
startTime = 0;
stopTime = 0;
if (QueryPerformanceFrequency(out freq) == false)
{
// 不支持高性能計數(shù)器
throw new Win32Exception();
}
}
// 開始計時器
public void Start()
{
// 來讓等待線程工作
Thread.Sleep(0);
QueryPerformanceCounter(out startTime);
}
// 停止計時器
public void Stop()
{
QueryPerformanceCounter(out stopTime);
}
// 返回計時器經(jīng)過時間(單位:秒)
public double Duration
{
get
{
return (double)(stopTime - startTime) / (double)freq;
}
}
}
}
上面封裝類的使用方法:
HighTimer pt = new HighTimer(); // 創(chuàng)建新的 HighTimer 對象
pt.Start(); // 啟動計時器
Console.WriteLine("Test/n"); // 需要計時的代碼
pt.Stop(); // 停止計時器
Console.WriteLine("Duration: {0} sec/n", pt.Duration); // 打印需要計時部分代碼的用時