一个 C# 获取高精度时间类(调用API QueryP*)

时间:2022-02-27 17:20:13

如果你觉得用 DotNet 自带的 DateTime 获取的时间精度不够,解决的方法是通过调用 QueryPerformanceFrequency 和 QueryPerformanceCounter这两个API来实现。

QueryPerformanceCounter 最小分辨率: 1/1193182 秒
API 开销: 1.92761875388667E-05 秒

多个语句执行之前 GetTickCount 或 timeGetTime 记录的更改。实际的循环数因操作系统正在执行的后台任务而异。
另一方面,QueryPerformanceCounter 更改,该值指示在高分辨率的时间中其用途的连续 API 调用之间的值。在这种情况下,分辨率是一个 microsecond 的顺序。因为系统依赖于分辨率,不存在,它测量标准单元。您必须通过确定的秒数经过 QueryPerformanceFrequency 划分不同之处。在上述情况只调用 API 的开销是关于 19 微秒为单位)。这将不得不上进行减法运算.

一个 C# 获取高精度时间类(调用API QueryP*)一个 C# 获取高精度时间类(调用API QueryP*)
Code//引用的命名空间
using System.Runtime.InteropServices;
using System.Security;
////////////////////////////
/// <summary>
/// 定义一个高精度的时间类
/// </summary>
public class Timer
{ #region private members
private long ticksPerSecond = 0;
private long elapsedTime = 0;
private long baseTime = 0;
#endregion
#region windows API
/// <summary>
/// 获取时间的精度
/// </summary>
/// <param name="PerformanceFrequency"></param>
/// <returns></returns>
[SuppressUnmanagedCodeSecurity]
[DllImport("kernel32")]
static private extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);
/// <summary>
/// 获取时间计数
/// </summary>
/// <param name="PerformanceCount"></param>
/// <returns></returns>
[SuppressUnmanagedCodeSecurity]
[DllImport("kernel32")]
static private extern bool QueryPerformanceCounter(ref long PerformanceCount);
#endregion
#region constructors
/// <summary>
/// new
/// </summary>
public Timer()
{
// Use QueryPerformanceFrequency to get frequency of the timer
if (!QueryPerformanceFrequency(ref ticksPerSecond))
throw new ApplicationException("Timer: Performance Frequency Unavailable");
Reset();
}
#endregion
#region public methods
/// <summary>
/// 重置时间相关计数器
/// </summary>
public void Reset()
{
long time = 0;
QueryPerformanceCounter(ref time);
baseTime = time;
elapsedTime = 0;
}
/// <summary>
/// 获取当前与最近一次 reset 时间差
/// </summary>
/// <returns>The time since last reset.</returns>
public double GetTime()
{
long time = 0;
QueryPerformanceCounter(ref time);
return (double)(time - baseTime) / (double)ticksPerSecond;
}
/// <summary>
/// 获取当前系统的时间 ticks 数
/// </summary>
/// <returns>The current time in seconds.</returns>
public double GetAbsoluteTime()
{
long time = 0;
QueryPerformanceCounter(ref time);
return (double)time / (double)ticksPerSecond;
}
/// <summary>
/// 获取此次与上次调用此方法的两次时间差
/// </summary>
/// <returns>The number of seconds since last call of this function.</returns>
public double GetElapsedTime()
{
long time = 0;
QueryPerformanceCounter(ref time);
double absoluteTime = (double)(time - elapsedTime) / (double)ticksPerSecond;
elapsedTime = time;
return absoluteTime;
}
#endregion
}

调用代码举例:

Timer t = new Timer();

double time = t.GetAbsoluteTime();

t.GetElapsedTime();

t.Reset();

t.GetTime();

////////////////////////////////////////////////////

在某些计算机上,由 QueryPerformanceFrequency 返回的结果将作为 CPU 的时钟速度。在处理器运行速度超过 2.1 GHz 的计算机上,该频率值需要至少 32 位的精度。某些程序将 QueryPerformanceFrequency 的结果用作经过签署的整数值,该值只有 31 位精度并带有符号标志。这些程序在这些较快的 CPU 上无法正确运行。要避免出现此问题,程序必须使用由 QueryPerformanceFrequencyQueryPerformanceCounter 返回的所有64 位。

有关超线程技术的更多信息,请访问下面的 Intel Web 站点:

http://cedar.intel.com/cgi-bin/ids.dll/topic.jsp?catCode=CDN