时间的函数Sleep,clock,GetTickCount,QueryPerformanceCounter

来源:互联网 发布:怎么提升淘宝买家等级 编辑:程序博客网 时间:2024/06/05 17:08

http://blog.csdn.net/augusdi/article/details/10960231


介绍

       我 们在衡量一个函数运行时间,或者判断一个算法的时间效率,或者在程序中我们需要一个定时器,定时执行一个特定的操作,比如在多媒体中,比如在游戏中等,都 会用到时间函数。还比如我们通过记录函数或者算法开始和截至的时间,然后利用两者之差得出函数或者算法的运行时间。编译器和操作系统为我们提供了很多时间 函数,这些时间函数的精度也是各不相同的,所以,如果我们想得到准确的结果,必须使用合适的时间函数。现在我就介绍windows下的几种常用时间函数。

1:Sleep函数

    使用:Sleep(1000),在Windows和Linux下1000代表的含义并不相同,Windows下的表示1000毫秒,也就是1秒钟;Linux下表示1000秒,Linux下使用毫秒级别的函数可以使用usleep。

    原理:Sleep函数是使调用Sleep函数的线程休眠,线程主动放弃时间片。当经过指定的时间间隔后,再启动线程,继续执行代码。Sleep函数并不能起到定时的作用,主要作用是延时。在一些多线程中可能会看到sleep(0);其主要目的是让出时间片。

    精度:Sleep函数的精度非常低,当系统越忙它精度也就越低,有时候我们休眠1秒,可能3秒后才能继续执行。它的精度取决于线程自身优先级、其他线程的优先级,以及线程的数量等因素。

2:MFC下的timer事件

    使用:1.调用函数SetTimer()设置定时间隔,如SetTimer(0,100,NULL)即为设置100毫秒的时间间隔;2.在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成时间到时的操作。

    原理:同Sleep函数一样。不同的是timer是一个定时器,可以指定回调函数,默认为OnTimer()函数。

    精度:timer事件的精度范围在毫米级别,系统越忙其精度也就越差。

3:C语言下的Time

    使用:time_t t;time(&t);Time函数是获取当前时间。

    原理:time函数主要用于获取当前时间,比如我们做一个电子时钟程序,就可以使用此函数,获取系统当前的时间。

    精度:秒级别

4:COM对象中的COleDateTime,COleDateTimeSpan类

    使用:

[cpp] view plain copy
  1. COleDateTime start_time = COleDateTime::GetCurrentTime();  
  2. COleDateTimeSpan end_time = COleDateTime::GetCurrentTime()-start_time;  
  3. While(end_time.GetTotalSeconds() < 2)  
  4. {  
  5. // 处理延时或定时期间能处理其他的消息  
  6. DoSomething()  
  7. end_time = COleDateTime::GetCurrentTime-start_time;  
  8. }  

     原理:以上代表延时2秒,而这两秒内我们可以循环调用DoSomething(),从而实现在延时的时候我们也能够处理其他的函数,或者消息。COleDateTime,COleDateTimeSpan是MFC中CTime,CTimeSpan在COM中的应用,所以,上面的方法对于CTime,CTimeSpan同样有效。

    精度:秒级别

5:C语言下的时钟周期clock()

    使用:   

[cpp] view plain copy
  1. clock_t start = clock();  
  2. Sleep(100);  
  3. clock_t end = clock();  
  4. double d = (double)(start - end) / CLOCKS_PER_SEC;  

    原理:clock()是获取计算机启动后的时间间隔。

    精度:ms级别,对于短时间内的定时或者延时可以达到ms级别,对于时间比较长的定时或者延迟精度还是不够。在windows下CLOCKS_PER_SEC为1000。

6:Windows下的GetTickCount()

    使用:  

[cpp] view plain copy
  1. DWORD start = GetTickCount();  
  2. Sleep(100);  
  3. DWORD end = GetTickCount();  

    原理:GetTickCount()是获取系统启动后的时间间隔。通过进入函数开始定时,到退出函数结束定时,从而可以判断出函数的执行时间,这种时间也并非是函数或者算法的真实执行时间,因为在函数和算法线程不可能一直占用CPU,对于所有判断执行时间的函数都是一样,不过基本上已经很准确,可以通过查询进行定时。GetTickCount()和Clock()函数是向主板BIOS要real time clock时间,会有中断产生,以及延迟问题。

    精度:WindowsNT 3.5以及以后版本精度是10ms,它的时间精度比clock函数的要高,GetTickCount()常用于多媒体中。

7:Windows下timeGetTime

    使用:需要包含Mmsystem.h,Windows.h,加入静态库Winmm.lib.

[cpp] view plain copy
  1. timeBeginPeriod(1);  
  2. DWORD start = timeGetTime();  
  3. Sleep(100);  
  4. DWORD end = timeGetTime();  
  5. timeEndPeriod(1);  

    原理:timeGetTime也时常用于多媒体定时器中,可以通过查询进行定时。通过查询进行定时,本身也会影响定时器的定时精度。

    精度:毫秒,与GetTickCount()相当。但是和GetTickCount相比,timeGetTime可以通过timeBeginPeriod,timeEndPeriod设置定时器的最小解析精度, timeBeginPeriod,timeEndPeriod必须成对出现。

8:windows下的timeSetEvent

    使用:还记的VC下的Timer吗?Timer是一个定时器,而以上我们提到几种时间函数或者类型,实现定时功能只能通过轮训来实现,也就是必须另外创建一个线程单独处理,这样会影响定时精度,好在windows提供了内置的定时器timeSetEvent,函数原型为

MMRESULT timeSetEvent( UINT uDelay, //以毫秒指定事件的周期
UINT uResolution, //以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms
LPTIMECALLBACK lpTimeProc, //指向一个回调函数
WORD dwUser, //存放用户提供的回调数据
UINT fuEvent )// 标志参数,TIME_ONESHOT:执行一次;TIME_PERIODIC:周期性执行

       具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在 lpFunction回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。

    原理:可以理解为代回调函数的timeGetTime

    精度:毫秒,timeSetEvent可以通过timeBeginPeriod,timeEndPeriod设置定时器的最小解析精度, timeBeginPeriod,timeEndPeriod必须成对出现。
9:高精度时控函数QueryPerformanceFrequency,QueryPerformanceCounter

    使用:

[cpp] view plain copy
  1. LARGE_INTEGER m_nFreq;  
  2. LARGE_INTEGER m_nBeginTime;  
  3. LARGE_INTEGER nEndTime;  
  4. QueryPerformanceFrequency(&m_nFreq); // 获取时钟周期  
  5. QueryPerformanceCounter(&m_nBeginTime); // 获取时钟计数  
  6. Sleep(100);  
  7. QueryPerformanceCounter(&nEndTime);  
  8. cout << (nEndTime.QuadPart-m_nBeginTime.QuadPart)*1000/m_nFreq.QuadPart << endl;  
     原理:CPU上也有一个计数器,以机器的clock为单位,可以通过rdtsc读取,而不用中断,因此其精度与系统时间相当。

    精度:计算机获取硬件支持,精度比较高,可以通过它判断其他时间函数的精度范围。

10小结:

以上提到常用的9种时间函数,由于他们的用处不同,所以他们的精度也不尽相同,所以如果简单的延时可以用Sleep函数,稍微准确的延时可以使用clock函数,GetTickCount函数,更高级的实用timeGetTime函数;简单的定时事件可以用Timer,准确地可以用timeSetEvent;或取一般系统时间可以通time,或者CTime,或者COleDateTime,获取准确的时间可以用clock,或者GetTickCount函数,或者timeGetTime函数,而获取准确地系统时间要使用硬件支持的QueryPerformanceFrequency函数,QueryPerformanceCounter函数。

11 一段简单的代码来实现精度试验

[cpp] view plain copy
  1. int main()  
  2. {  
  3.       // 初始化代码  
  4.       ......  
  5.       int i = 0;  
  6.       while(i++ < 1000)  
  7.       {  
  8.              // 获取时间代码  
  9.              ......  
  10.              printf(...); // 将时间打出  
  11.       }  
  12. }  
通过结果可以看出Sleep, GetTickCount都是10~35ms左右的时间跳跃,timeGetTime为1ms,QueryPerformanceCounter和QueryPerformanceFrequency根据CPU频率计时,可以到100ns。

说明Windows中常用的计时函数中,标准计时函数(Sleep, GetTickCount)精度100ms, 多媒体时钟timeGetTime精度1ms,系统晶振大概可以到1us或100ns左右。

可以用来做定时器的计时函数一般都在标准计时的精度范围(CreateWaitableTimer),只有多媒体时钟定时器要高一些。如果想要更高精度的定时器,目前看来Windows没有提供,但是,我们可以通过开发更底层的驱动来获得应用层的高精度定时器,大概可以精确到10us~100us


======================================================================

http://blog.csdn.net/augusdi/article/details/10960231


实现毫秒级和纳秒级计数的几个API--timeGetTime、GetTickCount、QueryPerformanceCoun
http://club.excelhome.NET/thread-907289-1-1.html
(出处: ExcelHome技术论坛)


本文在此基础上做了少量改动,以更好地演示几个API的计时效果。

窗体上放一个命令按钮。窗体代码如下:

Option Explicit

Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Declare Function QueryPerformanceCounter Lib "kernel32 " (lpPerformanceCount As Any) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32 " (lpFrequency As Any) As Long

Private Declare Sub Sleep Lib "KERNEL32.dll" (ByVal dwMilliseconds As Long)

Private Sub Command1_Click()
  timeCount
End Sub

Sub timeCount()
    Dim curFrequency As Currency
    Dim curStart As Currency
    Dim curEnd As Currency
    Dim delayms%
    
'    delayms = 66
'    delayms = 1
    Randomize
    delayms = Int((1000 - 1 + 1) * Rnd + 1)
    Me.Caption = "要求 sleep " & delayms & "毫秒,实际结果是:"

    QueryPerformanceFrequency curFrequency
    QueryPerformanceCounter curStart            '精度100ns
    Sleep delayms
    QueryPerformanceCounter curEnd
    MsgBox "QueryPerformanceCounter计时: " & (curEnd - curStart) / curFrequency * 1000 & "毫秒"
    
    curStart = Timer               '精度55ms
    Sleep delayms
    MsgBox "Timer计时: " & (Timer - curStart) * 1000 & "毫秒"
    
    curStart = GetTickCount        '精度55ms
    Sleep delayms
    MsgBox "GetTickCount计时: " & (GetTickCount - curStart) & "毫秒"
    
    curStart = timeGetTime         '精度10ms
    Sleep delayms
    MsgBox "timeGetTime计时: " & (timeGetTime - curStart) & "毫秒"

    Me.Caption = "请继续。。。"
End Sub


0 0