浅谈.NET中可用的定时器和计时器【下篇】
上篇介绍了.net中可用的定时器,本片主要介绍.net中可用的计时器。
- 第一种方法:使用Stopwatch
Stopwatch 在基础计时器机制中对计时器的刻度进行计数,从而测量运行时间。如果安装的硬件和操作系统支持高分辨率性能的计数器,则 Stopwatch 类将使用该计数器来测量运行时间;否则,Stopwatch 类将使用系统计数器来测量运行时间。使用 Frequency 和 IsHighResolution 两个静态字段可以确定实现 Stopwatch 计时的精度和分辨率。
实际上它里面就是将QueryPerformanceCounter、QueryPerformanceFrequency两个WIN API封装了一下,如果硬件支持高精度,就调用QueryPerformanceCounter,如果不支持就用DateTime.Ticks来计算。
简单用法介绍:
using System; using System.Diagnostics; using System.Threading; class Program { static void Main(string[] args) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); Thread.Sleep(10000); stopWatch.Stop(); // Get the elapsed time as a TimeSpan value. TimeSpan ts = stopWatch.Elapsed; // Format and display the TimeSpan value. string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Console.WriteLine("RunTime " + elapsedTime); } }
- 第二种方法:使用Environment.TickCount
Gets the number of milliseconds elapsed since the system started.获取系统启动后经过的毫秒数。经反编译猜测它可能也是调用的GetTickCount,但是它的返回值是int,而GetTickCount与timeGetTime方法的原型中返回值是DWORD,对应C#中的uint,难道.NET对System.Environment.TickCount另外还做了什么处理么?
缺点:与GetTickCount一样,受返回值的最大位数限制。
简答使用方法:
int aa = System.Environment.TickCount; Thread.Sleep(2719); Console.WriteLine(System.Environment.TickCount - aa); //单位毫秒
- 第三种方法:调用WIN API中的GetTickCount
[DllImport("kernel32")] static extern uint GetTickCount();
从操作系统启动到现在所经过的毫秒数,精度为1毫秒,存在一定的误差。因为返回值是uint,最大值是2的32次方,因此如果服务器连续开机大约49天以后,该方法取得的返回值会归零。
简单使用方法:
uint s1 = GetTickCount(); Thread.Sleep(2719); Console.WriteLine(GetTickCount() - s1); //单位毫秒
- 第四种方法:调用WIN API中的timeGetTime
[DllImport("winmm")] static extern uint timeGetTime();
常用于多媒体定时器中,与GetTickCount类似,也是返回操作系统启动到现在所经过的毫秒数,精度为1毫秒。一般默认的精度不止1毫秒(不同操作系统有所不同),需要调用timeBeginPeriod与timeEndPeriod来设置精度。
[DllImport("winmm")] static extern void timeBeginPeriod(int t); [DllImport("winmm")] static extern void timeEndPeriod(int t);
和GetTickCount一样,受返回值的最大位数限制。
简单使用方法:
timeBeginPeriod(1); uint start = timeGetTime(); Thread.Sleep(2719); Console.WriteLine(timeGetTime() - start); //单位毫秒 timeEndPeriod(1);
- 第五种方法:Win32 API 使用QueryPerformanceCounter() 和 QueryPerformanceFrequency() 方法支持高精度计时。
这些方法,比“标准的”毫秒精度的计时方法如 GetTickCount() 之类有高得多的精度。另一方面来说,在 C# 中使用“非托管”的 API 函数会有一定的开销,但比起使用一点都不精确的 GetTickCount() API 函数来说要好得多了。
第一个函数 QueryPerformanceCounter() 查询任意时刻高精度计数器的实际值。第二个函数 QueryPerformanceFrequency() 返回高精度计数器每秒的计数值。
然后通过将差除以每秒计数值(高精度计时器频率),就可以计算经过的时间了。duration = (stop - start) / frequency,经过时间 = (停止时间 - 开始时间) / 频率。
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); // 打印需要计时部分代码的用时
还有其他的一些方法,譬如cpu的时间戳计时等。
就总结这么多,希望对你有帮助~