我们在平时的项目中,时常会遇到这样的问题,当我们要评价一个算法的好坏时(这里指的是时间复杂度量级相同的两个算法);当我们要测试一段代码的性能时。。。我们都需要一个高精度的时间。如何来得到一个高精度的时间,而且又不影响我们的测试准确性呢?平时大家可能采用的方法是:new两个time,然后两个Time相减,得到一个TimeSpan,这样就可以得到一个毫秒级的时间(当然了,这个是一个并不精确的毫秒级时间),但是,那如果你要求的精度更好,需要达到微秒,纳秒级呢?这时候使用系统提供的Time类就不行了。
我曾经也遇到过类似的问题,于是在这里就封装了自己的Code,提供一个使用方便,高效,精确的纳秒级计时器。
我采用的方法是使用两个Win32函数来实现的:
QueryPerformanceCounter():此函数用于获取精确的性能计数器数值。
QueryPerformanceFrequency():返回硬件支持的高精度计数器的频率(你可以理解为查询CPU的主频)。
这两个函数是Win32标准库函数,我们要使用它就需要P/Invoke技术。P/Invoke技术是由微软提供的用于Native和Managed之间资源和函数互访的一项技术。在.net平台中就是DllImport。
下面就是主要的类代码了:
using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace RedFox66.Utility
{
class PerformanceTimer
{
[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 PerformanceTimer()
{
startTime = 0;
stopTime = 0;
if (QueryPerformanceFrequency(out freq) == false)
{
throw new Exception("Timer not supported.");
}
}
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;
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
usingSystem;
usingSystem.Threading;
usingSystem.Runtime.InteropServices;
namespaceRedFox66.Utility
{
classPerformanceTimer
{
[DllImport("Kernel32.dll")]
privatestaticexternboolQueryPerformanceCounter(
outlonglpPerformanceCount);
[DllImport("Kernel32.dll")]
privatestaticexternboolQueryPerformanceFrequency(
outlonglpFrequency);
privatelongstartTime,stopTime;
privatelongfreq;
publicPerformanceTimer()
{
startTime=0;
stopTime=0;
if(QueryPerformanceFrequency(outfreq)==false)
{
thrownewException("Timer not supported.");
}
}
publicvoidStart()
{
Thread.Sleep(0);
QueryPerformanceCounter(outstartTime);
}
publicvoidStop()
{
QueryPerformanceCounter(outstopTime);
}
publicdoubleDuration
{
get
{
return(double)(stopTime-startTime)/(double)freq;
}
}
}
}
有了这个代码我们就可以获得高精度时间,示例代码如下:
private void Test()
{
PerformanceTimer timer = new PerformanceTimer();
timer.Start();
///中间需要计时的代码
///......
///中间需要计时的代码
timer.Stop();
Console.Write("{0:F}t", timer.Duration);//输出时间。。。
}
1
2
3
4
5
6
7
8
9
10
privatevoidTest()
{
PerformanceTimertimer=newPerformanceTimer();
timer.Start();
///中间需要计时的代码
///......
///中间需要计时的代码
timer.Stop();
Console.Write("{0:F}t",timer.Duration);//输出时间。。。
}
好了,到这里计时器的工作就全部完成了,希望对大家有帮助。
需要源代码的可以到这里下载: