首页 > 代码库 > .net平台下获取高精度时间类

.net平台下获取高精度时间类

原文:http://www.it118.org/specials/321869dd-98cb-431b-b6d2-82d973cd739d/d940a15c-0d36-4369-8de0-b07cf3f3fd5f.htm

 

 

前言:.NET 2.0前运行库中不存在高精度的计时器,而您又需要它,解决的方法是通过调用QueryPerformanceFrequency  QueryPerformanceCounter这两个Win32 API来实现。在.NET 2.0时,stopwatch类也可实现高精度计时,请参考:《使用Stopwatch类实现高精度计时》

.NET运行库具有一个属性—— System.Environment.Tickcount,您可以使用它计算时间。该属性返回计算机最近一次启动之后,已用时间滴答数(ms)。一开始,您可能觉得它是一个非常好的工具。但是,它有一个相当显著的缺陷,即该属性并不是每毫秒都更新。

该属性的更新频率通常依赖于计时器的分辨率。在该案例中,tick-count属性的分辨率是15 ms。如果您在一个循环中持续访问该属性,则在更新之前的每15ms它返回相同的值,然后在下一次更新之前的另一个15ms中,它返回一个新的值。现代的计算机每秒能够执行非常巨大的计算量,15ms的分辨率将使得您的计算看上去好像“停停动动的”。

警告:

如果希望在应用程序中使用TickCount属性,那么必须明确它返回的是一个无符号整数值。因为该属性是计算机启动之后已用时间的滴答数,所以如果计算机运行了非常长的时间 (例如超过25天),该属性将返回一个负数。如果您没有考虑这种情况,将使得正在使用的公式出错。在更长的一段时间之后,该值将重新归0。

这里您需要的是一个具有更高分辨率的计时器。一个分辨率为1ms的计时器是您非常好的选择。

.NET 2.0前运行库中不存在高精度的计时器,而您又需要它,解决的方法是通过调用QueryPerformanceFrequency  QueryPerformanceCounter这两个Win32 API来实现。

  1. using System;  
  2. using System.Runtime.InteropServices;  
  3.   
  4. internal sealed class AccurateTimerHelper  
  5. {  
  6.     public AccurateTimerHelper()  
  7.     {  
  8.         TicksPerSecond = this.GetTicksPerSecond();  
  9.         this.BaseTime = this.GetTime();  
  10.     }  
  11.   
  12.     [DllImport("kernel32.dll", EntryPoint="QueryPerformanceCounter")]  
  13.     private static extern int QueryPerformanceCounter(ref long lpPerformanceCount);  
  14.     [DllImport("kernel32.dll", EntryPoint="QueryPerformanceFrequency")]  
  15.     private static extern int QueryPerformanceFrequency(ref long A_0);  
  16.   
  17.   
  18.     public long GetElapsedTime()  
  19.     {  
  20.         return (long)((((double)(this.GetTime() - this.BaseTime)) / ((double)TicksPerSecond)) * 10000);  
  21.     }  
  22.   
  23.     private long GetTime()  
  24.     {  
  25.         long time = 0;  
  26.         if (AccurateTimerHelper.QueryPerformanceCounter(ref time) == 0)  
  27.         {  
  28.             throw new NotSupportedException("Error while querying the high-resolution performance counter.");  
  29.         }  
  30.         return time;  
  31.     }  
  32.   
  33.     private long GetTicksPerSecond()  
  34.     {  
  35.         long ticksPerSecond = 0;  
  36.         if (AccurateTimerHelper.QueryPerformanceFrequency(ref ticksPerSecond) == 0)  
  37.         {  
  38.             throw new NotSupportedException("Error while querying the performance counter frequency.");  
  39.         }  
  40.         return ticksPerSecond;  
  41.     }  
  42.       
  43.   
  44.     private long BaseTime  
  45.     {  
  46.         get  
  47.         {  
  48.             return baseTime;              
  49.         }  
  50.         set  
  51.         {  
  52.             this.baseTime = value;   
  53.         }  
  54.     }  
  55.   
  56.     private long TicksPerSecond  
  57.     {  
  58.         get  
  59.         {  
  60.             return this.ticksPerSecond;  
  61.         }  
  62.         set  
  63.         {  
  64.             ticksPerSecond = value;  
  65.         }  
  66.     }  
  67.   
  68.     private long baseTime;  
  69.     private long ticksPerSecond;  
  70. }  

调用很简单:  

    1. AccurateTimerHelper atHelper = new AccurateTimerHelper();  
    2. /* 
    3. //进行很多费时操作 
    4. */  
    5. atHelper.GetElapsedTime()