浅谈.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的时间戳计时等。

  就总结这么多,希望对你有帮助~

posted @ 2012-08-05 11:54  DebugLZQ  阅读(1974)  评论(1编辑  收藏  举报